Path: blob/main/cddl/contrib/opensolaris/lib/libdtrace/common/dt_program.c
39563 views
/*1* CDDL HEADER START2*3* The contents of this file are subject to the terms of the4* Common Development and Distribution License (the "License").5* You may not use this file except in compliance with the License.6*7* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE8* or http://www.opensolaris.org/os/licensing.9* See the License for the specific language governing permissions10* and limitations under the License.11*12* When distributing Covered Code, include this CDDL HEADER in each13* file and include the License file at usr/src/OPENSOLARIS.LICENSE.14* If applicable, add the following below this CDDL HEADER, with the15* fields enclosed by brackets "[]" replaced with your own identifying16* information: Portions Copyright [yyyy] [name of copyright owner]17*18* CDDL HEADER END19*/2021/*22* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.23* Copyright (c) 2011 by Delphix. All rights reserved.24*/2526#include <unistd.h>27#include <strings.h>28#include <stdlib.h>29#include <errno.h>30#include <assert.h>31#include <ctype.h>32#ifdef illumos33#include <alloca.h>34#endif3536#include <dt_impl.h>37#include <dt_program.h>38#include <dt_printf.h>39#include <dt_provider.h>4041dtrace_prog_t *42dt_program_create(dtrace_hdl_t *dtp)43{44dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t));4546if (pgp != NULL) {47dt_list_append(&dtp->dt_programs, pgp);48} else {49(void) dt_set_errno(dtp, EDT_NOMEM);50return (NULL);51}5253/*54* By default, programs start with DOF version 1 so that output files55* containing DOF are backward compatible. If a program requires new56* DOF features, the version is increased as needed.57*/58pgp->dp_dofversion = DOF_VERSION_1;5960return (pgp);61}6263void64dt_program_destroy(dtrace_hdl_t *dtp, dtrace_prog_t *pgp)65{66dt_stmt_t *stp, *next;67uint_t i;6869for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {70next = dt_list_next(stp);71dtrace_stmt_destroy(dtp, stp->ds_desc);72dt_free(dtp, stp);73}7475for (i = 0; i < pgp->dp_xrefslen; i++)76dt_free(dtp, pgp->dp_xrefs[i]);7778dt_free(dtp, pgp->dp_xrefs);79dt_list_delete(&dtp->dt_programs, pgp);80dt_free(dtp, pgp);81}8283/*ARGSUSED*/84void85dtrace_program_info(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,86dtrace_proginfo_t *pip)87{88dt_stmt_t *stp;89dtrace_actdesc_t *ap;90dtrace_ecbdesc_t *last = NULL;9192if (pip == NULL)93return;9495bzero(pip, sizeof (dtrace_proginfo_t));9697if (dt_list_next(&pgp->dp_stmts) != NULL) {98pip->dpi_descattr = _dtrace_maxattr;99pip->dpi_stmtattr = _dtrace_maxattr;100} else {101pip->dpi_descattr = _dtrace_defattr;102pip->dpi_stmtattr = _dtrace_defattr;103}104105for (stp = dt_list_next(&pgp->dp_stmts); stp; stp = dt_list_next(stp)) {106dtrace_ecbdesc_t *edp = stp->ds_desc->dtsd_ecbdesc;107108if (edp == last)109continue;110last = edp;111112pip->dpi_descattr =113dt_attr_min(stp->ds_desc->dtsd_descattr, pip->dpi_descattr);114115pip->dpi_stmtattr =116dt_attr_min(stp->ds_desc->dtsd_stmtattr, pip->dpi_stmtattr);117118/*119* If there aren't any actions, account for the fact that120* recording the epid will generate a record.121*/122if (edp->dted_action == NULL)123pip->dpi_recgens++;124125for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {126if (ap->dtad_kind == DTRACEACT_SPECULATE) {127pip->dpi_speculations++;128continue;129}130131if (DTRACEACT_ISAGG(ap->dtad_kind)) {132pip->dpi_recgens -= ap->dtad_arg;133pip->dpi_aggregates++;134continue;135}136137if (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind))138continue;139140if (ap->dtad_kind == DTRACEACT_DIFEXPR &&141ap->dtad_difo->dtdo_rtype.dtdt_kind ==142DIF_TYPE_CTF &&143ap->dtad_difo->dtdo_rtype.dtdt_size == 0)144continue;145146pip->dpi_recgens++;147}148}149}150151int152dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,153dtrace_proginfo_t *pip)154{155dtrace_enable_io_t args;156void *dof;157int n, err;158159dtrace_program_info(dtp, pgp, pip);160161if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL)162return (-1);163164args.dof = dof;165args.n_matched = 0;166n = dt_ioctl(dtp, DTRACEIOC_ENABLE, &args);167dtrace_dof_destroy(dtp, dof);168169if (n == -1) {170switch (errno) {171case EINVAL:172err = EDT_DIFINVAL;173break;174case EFAULT:175err = EDT_DIFFAULT;176break;177case E2BIG:178err = EDT_DIFSIZE;179break;180case EBUSY:181err = EDT_ENABLING_ERR;182break;183default:184err = errno;185}186187return (dt_set_errno(dtp, err));188}189190if (pip != NULL)191pip->dpi_matches += args.n_matched;192193return (0);194}195196static void197dt_ecbdesc_hold(dtrace_ecbdesc_t *edp)198{199edp->dted_refcnt++;200}201202void203dt_ecbdesc_release(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)204{205if (--edp->dted_refcnt > 0)206return;207208dt_difo_free(dtp, edp->dted_pred.dtpdd_difo);209assert(edp->dted_action == NULL);210dt_free(dtp, edp);211}212213dtrace_ecbdesc_t *214dt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)215{216dtrace_ecbdesc_t *edp;217218if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) {219(void) dt_set_errno(dtp, EDT_NOMEM);220return (NULL);221}222223edp->dted_probe = *pdp;224dt_ecbdesc_hold(edp);225return (edp);226}227228dtrace_stmtdesc_t *229dtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)230{231dtrace_stmtdesc_t *sdp;232233if ((sdp = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL)234return (NULL);235236dt_ecbdesc_hold(edp);237sdp->dtsd_ecbdesc = edp;238sdp->dtsd_descattr = _dtrace_defattr;239sdp->dtsd_stmtattr = _dtrace_defattr;240241return (sdp);242}243244dtrace_actdesc_t *245dtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)246{247dtrace_actdesc_t *new;248dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;249250if ((new = dt_alloc(dtp, sizeof (dtrace_actdesc_t))) == NULL)251return (NULL);252253if (sdp->dtsd_action_last != NULL) {254assert(sdp->dtsd_action != NULL);255assert(sdp->dtsd_action_last->dtad_next == NULL);256sdp->dtsd_action_last->dtad_next = new;257} else {258dtrace_actdesc_t *ap = edp->dted_action;259260assert(sdp->dtsd_action == NULL);261sdp->dtsd_action = new;262263while (ap != NULL && ap->dtad_next != NULL)264ap = ap->dtad_next;265266if (ap == NULL)267edp->dted_action = new;268else269ap->dtad_next = new;270}271272sdp->dtsd_action_last = new;273bzero(new, sizeof (dtrace_actdesc_t));274new->dtad_uarg = (uintptr_t)sdp;275276return (new);277}278279int280dtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp)281{282dt_stmt_t *stp = dt_alloc(dtp, sizeof (dt_stmt_t));283284if (stp == NULL)285return (-1); /* errno is set for us */286287dt_list_append(&pgp->dp_stmts, stp);288stp->ds_desc = sdp;289290return (0);291}292293int294dtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,295dtrace_stmt_f *func, void *data)296{297dt_stmt_t *stp, *next;298int status = 0;299300for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {301next = dt_list_next(stp);302if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0)303break;304}305306return (status);307}308309void310dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)311{312dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;313314/*315* We need to remove any actions that we have on this ECB, and316* remove our hold on the ECB itself.317*/318if (sdp->dtsd_action != NULL) {319dtrace_actdesc_t *last = sdp->dtsd_action_last;320dtrace_actdesc_t *ap, *next;321322assert(last != NULL);323324for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {325if (ap == sdp->dtsd_action)326break;327328if (ap->dtad_next == sdp->dtsd_action)329break;330}331332assert(ap != NULL);333334if (ap == edp->dted_action)335edp->dted_action = last->dtad_next;336else337ap->dtad_next = last->dtad_next;338339/*340* We have now removed our action list from its ECB; we can341* safely destroy the list.342*/343last->dtad_next = NULL;344345for (ap = sdp->dtsd_action; ap != NULL; ap = next) {346assert(ap->dtad_uarg == (uintptr_t)sdp);347dt_difo_free(dtp, ap->dtad_difo);348next = ap->dtad_next;349dt_free(dtp, ap);350}351}352353if (sdp->dtsd_fmtdata != NULL)354dt_printf_destroy(sdp->dtsd_fmtdata);355dt_free(dtp, sdp->dtsd_strdata);356357dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc);358dt_free(dtp, sdp);359}360361typedef struct dt_header_info {362dtrace_hdl_t *dthi_dtp; /* consumer handle */363FILE *dthi_out; /* output file */364char *dthi_pmname; /* provider macro name */365char *dthi_pfname; /* provider function name */366int dthi_empty; /* should we generate empty macros */367} dt_header_info_t;368369static void370dt_header_fmt_macro(char *buf, const char *str)371{372for (;;) {373if (islower(*str)) {374*buf++ = *str++ + 'A' - 'a';375} else if (*str == '-') {376*buf++ = '_';377str++;378} else if (*str == '.') {379*buf++ = '_';380str++;381} else if ((*buf++ = *str++) == '\0') {382break;383}384}385}386387static void388dt_header_fmt_func(char *buf, const char *str)389{390for (;;) {391if (*str == '-') {392*buf++ = '_';393*buf++ = '_';394str++;395} else if ((*buf++ = *str++) == '\0') {396break;397}398}399}400401/*ARGSUSED*/402static int403dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data)404{405dt_header_info_t *infop = data;406dtrace_hdl_t *dtp = infop->dthi_dtp;407dt_probe_t *prp = idp->di_data;408dt_node_t *dnp;409char buf[DT_TYPE_NAMELEN];410char *fname;411const char *p;412int i;413414p = prp->pr_name;415for (i = 0; (p = strchr(p, '-')) != NULL; i++)416p++;417418fname = alloca(strlen(prp->pr_name) + 1 + i);419dt_header_fmt_func(fname, prp->pr_name);420421if (fprintf(infop->dthi_out, "extern void __dtrace_%s___%s(",422infop->dthi_pfname, fname) < 0)423return (dt_set_errno(dtp, errno));424425for (dnp = prp->pr_nargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) {426if (fprintf(infop->dthi_out, "%s",427ctf_type_name(dnp->dn_ctfp, dnp->dn_type,428buf, sizeof (buf))) < 0)429return (dt_set_errno(dtp, errno));430431if (i + 1 != prp->pr_nargc &&432fprintf(infop->dthi_out, ", ") < 0)433return (dt_set_errno(dtp, errno));434}435436if (i == 0 && fprintf(infop->dthi_out, "void") < 0)437return (dt_set_errno(dtp, errno));438439if (fprintf(infop->dthi_out, ");\n") < 0)440return (dt_set_errno(dtp, errno));441442if (fprintf(infop->dthi_out,443"#ifndef\t__sparc\n"444"extern int __dtraceenabled_%s___%s(void);\n"445"#else\n"446"extern int __dtraceenabled_%s___%s(long);\n"447"#endif\n",448infop->dthi_pfname, fname, infop->dthi_pfname, fname) < 0)449return (dt_set_errno(dtp, errno));450451return (0);452}453454/*ARGSUSED*/455static int456dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)457{458dt_header_info_t *infop = data;459dtrace_hdl_t *dtp = infop->dthi_dtp;460dt_probe_t *prp = idp->di_data;461char *mname, *fname;462const char *p;463int i;464465p = prp->pr_name;466for (i = 0; (p = strchr(p, '-')) != NULL; i++)467p++;468469mname = alloca(strlen(prp->pr_name) + 1);470dt_header_fmt_macro(mname, prp->pr_name);471472fname = alloca(strlen(prp->pr_name) + 1 + i);473dt_header_fmt_func(fname, prp->pr_name);474475if (fprintf(infop->dthi_out, "#define\t%s_%s(",476infop->dthi_pmname, mname) < 0)477return (dt_set_errno(dtp, errno));478479for (i = 0; i < prp->pr_nargc; i++) {480if (fprintf(infop->dthi_out, "arg%d", i) < 0)481return (dt_set_errno(dtp, errno));482483if (i + 1 != prp->pr_nargc &&484fprintf(infop->dthi_out, ", ") < 0)485return (dt_set_errno(dtp, errno));486}487488if (!infop->dthi_empty) {489if (fprintf(infop->dthi_out, ") \\\n\t") < 0)490return (dt_set_errno(dtp, errno));491492if (fprintf(infop->dthi_out, "__dtrace_%s___%s(",493infop->dthi_pfname, fname) < 0)494return (dt_set_errno(dtp, errno));495496for (i = 0; i < prp->pr_nargc; i++) {497if (fprintf(infop->dthi_out, "arg%d", i) < 0)498return (dt_set_errno(dtp, errno));499500if (i + 1 != prp->pr_nargc &&501fprintf(infop->dthi_out, ", ") < 0)502return (dt_set_errno(dtp, errno));503}504}505506if (fprintf(infop->dthi_out, ")\n") < 0)507return (dt_set_errno(dtp, errno));508509if (!infop->dthi_empty) {510if (fprintf(infop->dthi_out,511"#ifndef\t__sparc\n"512"#define\t%s_%s_ENABLED() \\\n"513"\t__dtraceenabled_%s___%s()\n"514"#else\n"515"#define\t%s_%s_ENABLED() \\\n"516"\t__dtraceenabled_%s___%s(0)\n"517"#endif\n",518infop->dthi_pmname, mname,519infop->dthi_pfname, fname,520infop->dthi_pmname, mname,521infop->dthi_pfname, fname) < 0)522return (dt_set_errno(dtp, errno));523524} else {525if (fprintf(infop->dthi_out, "#define\t%s_%s_ENABLED() (0)\n",526infop->dthi_pmname, mname) < 0)527return (dt_set_errno(dtp, errno));528}529530return (0);531}532533static int534dt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out)535{536dt_header_info_t info;537const char *p;538int i;539540if (pvp->pv_flags & DT_PROVIDER_IMPL)541return (0);542543/*544* Count the instances of the '-' character since we'll need to double545* those up.546*/547p = pvp->pv_desc.dtvd_name;548for (i = 0; (p = strchr(p, '-')) != NULL; i++)549p++;550551info.dthi_dtp = dtp;552info.dthi_out = out;553info.dthi_empty = 0;554555info.dthi_pmname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1);556dt_header_fmt_macro(info.dthi_pmname, pvp->pv_desc.dtvd_name);557558info.dthi_pfname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1 + i);559dt_header_fmt_func(info.dthi_pfname, pvp->pv_desc.dtvd_name);560561#ifdef __FreeBSD__562if (fprintf(out, "#include <sys/sdt.h>\n\n") < 0)563return (dt_set_errno(dtp, errno));564#endif565if (fprintf(out, "#if _DTRACE_VERSION\n\n") < 0)566return (dt_set_errno(dtp, errno));567568if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)569return (-1); /* dt_errno is set for us */570if (fprintf(out, "\n\n") < 0)571return (dt_set_errno(dtp, errno));572if (dt_idhash_iter(pvp->pv_probes, dt_header_decl, &info) != 0)573return (-1); /* dt_errno is set for us */574575if (fprintf(out, "\n#else\n\n") < 0)576return (dt_set_errno(dtp, errno));577578info.dthi_empty = 1;579580if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)581return (-1); /* dt_errno is set for us */582583if (fprintf(out, "\n#endif\n\n") < 0)584return (dt_set_errno(dtp, errno));585586return (0);587}588589int590dtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname)591{592dt_provider_t *pvp;593char *mfname, *p;594595if (fname != NULL) {596if ((p = strrchr(fname, '/')) != NULL)597fname = p + 1;598599mfname = alloca(strlen(fname) + 1);600dt_header_fmt_macro(mfname, fname);601if (fprintf(out, "#ifndef\t_%s\n#define\t_%s\n\n",602mfname, mfname) < 0)603return (dt_set_errno(dtp, errno));604}605606if (fprintf(out, "#include <unistd.h>\n\n") < 0)607return (-1);608609if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0)610return (-1);611612for (pvp = dt_list_next(&dtp->dt_provlist);613pvp != NULL; pvp = dt_list_next(pvp)) {614if (dt_header_provider(dtp, pvp, out) != 0)615return (-1); /* dt_errno is set for us */616}617618if (fprintf(out, "\n#ifdef\t__cplusplus\n}\n#endif\n") < 0)619return (dt_set_errno(dtp, errno));620621if (fname != NULL && fprintf(out, "\n#endif\t/* _%s */\n", mfname) < 0)622return (dt_set_errno(dtp, errno));623624return (0);625}626627628