16ff6d951SJohn Birrell /*
26ff6d951SJohn Birrell * CDDL HEADER START
36ff6d951SJohn Birrell *
46ff6d951SJohn Birrell * The contents of this file are subject to the terms of the
56ff6d951SJohn Birrell * Common Development and Distribution License (the "License").
66ff6d951SJohn Birrell * You may not use this file except in compliance with the License.
76ff6d951SJohn Birrell *
86ff6d951SJohn Birrell * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96ff6d951SJohn Birrell * or http://www.opensolaris.org/os/licensing.
106ff6d951SJohn Birrell * See the License for the specific language governing permissions
116ff6d951SJohn Birrell * and limitations under the License.
126ff6d951SJohn Birrell *
136ff6d951SJohn Birrell * When distributing Covered Code, include this CDDL HEADER in each
146ff6d951SJohn Birrell * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156ff6d951SJohn Birrell * If applicable, add the following below this CDDL HEADER, with the
166ff6d951SJohn Birrell * fields enclosed by brackets "[]" replaced with your own identifying
176ff6d951SJohn Birrell * information: Portions Copyright [yyyy] [name of copyright owner]
186ff6d951SJohn Birrell *
196ff6d951SJohn Birrell * CDDL HEADER END
206ff6d951SJohn Birrell */
216ff6d951SJohn Birrell
226ff6d951SJohn Birrell /*
231670a1c2SRui Paulo * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
2454727873SPedro F. Giffuni * Copyright (c) 2011 by Delphix. All rights reserved.
256ff6d951SJohn Birrell */
266ff6d951SJohn Birrell
276ff6d951SJohn Birrell #include <unistd.h>
286ff6d951SJohn Birrell #include <strings.h>
296ff6d951SJohn Birrell #include <stdlib.h>
306ff6d951SJohn Birrell #include <errno.h>
316ff6d951SJohn Birrell #include <assert.h>
326ff6d951SJohn Birrell #include <ctype.h>
33*bc96366cSSteven Hartland #ifdef illumos
346ff6d951SJohn Birrell #include <alloca.h>
35df5c121dSJohn Birrell #endif
366ff6d951SJohn Birrell
376ff6d951SJohn Birrell #include <dt_impl.h>
386ff6d951SJohn Birrell #include <dt_program.h>
396ff6d951SJohn Birrell #include <dt_printf.h>
406ff6d951SJohn Birrell #include <dt_provider.h>
416ff6d951SJohn Birrell
426ff6d951SJohn Birrell dtrace_prog_t *
dt_program_create(dtrace_hdl_t * dtp)436ff6d951SJohn Birrell dt_program_create(dtrace_hdl_t *dtp)
446ff6d951SJohn Birrell {
456ff6d951SJohn Birrell dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t));
466ff6d951SJohn Birrell
471670a1c2SRui Paulo if (pgp != NULL) {
486ff6d951SJohn Birrell dt_list_append(&dtp->dt_programs, pgp);
491670a1c2SRui Paulo } else {
506ff6d951SJohn Birrell (void) dt_set_errno(dtp, EDT_NOMEM);
511670a1c2SRui Paulo return (NULL);
521670a1c2SRui Paulo }
536ff6d951SJohn Birrell
546ff6d951SJohn Birrell /*
556ff6d951SJohn Birrell * By default, programs start with DOF version 1 so that output files
566ff6d951SJohn Birrell * containing DOF are backward compatible. If a program requires new
576ff6d951SJohn Birrell * DOF features, the version is increased as needed.
586ff6d951SJohn Birrell */
596ff6d951SJohn Birrell pgp->dp_dofversion = DOF_VERSION_1;
606ff6d951SJohn Birrell
616ff6d951SJohn Birrell return (pgp);
626ff6d951SJohn Birrell }
636ff6d951SJohn Birrell
646ff6d951SJohn Birrell void
dt_program_destroy(dtrace_hdl_t * dtp,dtrace_prog_t * pgp)656ff6d951SJohn Birrell dt_program_destroy(dtrace_hdl_t *dtp, dtrace_prog_t *pgp)
666ff6d951SJohn Birrell {
676ff6d951SJohn Birrell dt_stmt_t *stp, *next;
686ff6d951SJohn Birrell uint_t i;
696ff6d951SJohn Birrell
706ff6d951SJohn Birrell for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
716ff6d951SJohn Birrell next = dt_list_next(stp);
726ff6d951SJohn Birrell dtrace_stmt_destroy(dtp, stp->ds_desc);
736ff6d951SJohn Birrell dt_free(dtp, stp);
746ff6d951SJohn Birrell }
756ff6d951SJohn Birrell
766ff6d951SJohn Birrell for (i = 0; i < pgp->dp_xrefslen; i++)
776ff6d951SJohn Birrell dt_free(dtp, pgp->dp_xrefs[i]);
786ff6d951SJohn Birrell
796ff6d951SJohn Birrell dt_free(dtp, pgp->dp_xrefs);
806ff6d951SJohn Birrell dt_list_delete(&dtp->dt_programs, pgp);
816ff6d951SJohn Birrell dt_free(dtp, pgp);
826ff6d951SJohn Birrell }
836ff6d951SJohn Birrell
846ff6d951SJohn Birrell /*ARGSUSED*/
856ff6d951SJohn Birrell void
dtrace_program_info(dtrace_hdl_t * dtp,dtrace_prog_t * pgp,dtrace_proginfo_t * pip)866ff6d951SJohn Birrell dtrace_program_info(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
876ff6d951SJohn Birrell dtrace_proginfo_t *pip)
886ff6d951SJohn Birrell {
896ff6d951SJohn Birrell dt_stmt_t *stp;
906ff6d951SJohn Birrell dtrace_actdesc_t *ap;
916ff6d951SJohn Birrell dtrace_ecbdesc_t *last = NULL;
926ff6d951SJohn Birrell
936ff6d951SJohn Birrell if (pip == NULL)
946ff6d951SJohn Birrell return;
956ff6d951SJohn Birrell
966ff6d951SJohn Birrell bzero(pip, sizeof (dtrace_proginfo_t));
976ff6d951SJohn Birrell
986ff6d951SJohn Birrell if (dt_list_next(&pgp->dp_stmts) != NULL) {
996ff6d951SJohn Birrell pip->dpi_descattr = _dtrace_maxattr;
1006ff6d951SJohn Birrell pip->dpi_stmtattr = _dtrace_maxattr;
1016ff6d951SJohn Birrell } else {
1026ff6d951SJohn Birrell pip->dpi_descattr = _dtrace_defattr;
1036ff6d951SJohn Birrell pip->dpi_stmtattr = _dtrace_defattr;
1046ff6d951SJohn Birrell }
1056ff6d951SJohn Birrell
1066ff6d951SJohn Birrell for (stp = dt_list_next(&pgp->dp_stmts); stp; stp = dt_list_next(stp)) {
1076ff6d951SJohn Birrell dtrace_ecbdesc_t *edp = stp->ds_desc->dtsd_ecbdesc;
1086ff6d951SJohn Birrell
1096ff6d951SJohn Birrell if (edp == last)
1106ff6d951SJohn Birrell continue;
1116ff6d951SJohn Birrell last = edp;
1126ff6d951SJohn Birrell
1136ff6d951SJohn Birrell pip->dpi_descattr =
1146ff6d951SJohn Birrell dt_attr_min(stp->ds_desc->dtsd_descattr, pip->dpi_descattr);
1156ff6d951SJohn Birrell
1166ff6d951SJohn Birrell pip->dpi_stmtattr =
1176ff6d951SJohn Birrell dt_attr_min(stp->ds_desc->dtsd_stmtattr, pip->dpi_stmtattr);
1186ff6d951SJohn Birrell
1196ff6d951SJohn Birrell /*
1206ff6d951SJohn Birrell * If there aren't any actions, account for the fact that
1216ff6d951SJohn Birrell * recording the epid will generate a record.
1226ff6d951SJohn Birrell */
1236ff6d951SJohn Birrell if (edp->dted_action == NULL)
1246ff6d951SJohn Birrell pip->dpi_recgens++;
1256ff6d951SJohn Birrell
1266ff6d951SJohn Birrell for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
1276ff6d951SJohn Birrell if (ap->dtad_kind == DTRACEACT_SPECULATE) {
1286ff6d951SJohn Birrell pip->dpi_speculations++;
1296ff6d951SJohn Birrell continue;
1306ff6d951SJohn Birrell }
1316ff6d951SJohn Birrell
1326ff6d951SJohn Birrell if (DTRACEACT_ISAGG(ap->dtad_kind)) {
1336ff6d951SJohn Birrell pip->dpi_recgens -= ap->dtad_arg;
1346ff6d951SJohn Birrell pip->dpi_aggregates++;
1356ff6d951SJohn Birrell continue;
1366ff6d951SJohn Birrell }
1376ff6d951SJohn Birrell
1386ff6d951SJohn Birrell if (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind))
1396ff6d951SJohn Birrell continue;
1406ff6d951SJohn Birrell
1416ff6d951SJohn Birrell if (ap->dtad_kind == DTRACEACT_DIFEXPR &&
1426ff6d951SJohn Birrell ap->dtad_difo->dtdo_rtype.dtdt_kind ==
1436ff6d951SJohn Birrell DIF_TYPE_CTF &&
1446ff6d951SJohn Birrell ap->dtad_difo->dtdo_rtype.dtdt_size == 0)
1456ff6d951SJohn Birrell continue;
1466ff6d951SJohn Birrell
1476ff6d951SJohn Birrell pip->dpi_recgens++;
1486ff6d951SJohn Birrell }
1496ff6d951SJohn Birrell }
1506ff6d951SJohn Birrell }
1516ff6d951SJohn Birrell
1526ff6d951SJohn Birrell int
dtrace_program_exec(dtrace_hdl_t * dtp,dtrace_prog_t * pgp,dtrace_proginfo_t * pip)1536ff6d951SJohn Birrell dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
1546ff6d951SJohn Birrell dtrace_proginfo_t *pip)
1556ff6d951SJohn Birrell {
156df5c121dSJohn Birrell dtrace_enable_io_t args;
1576ff6d951SJohn Birrell void *dof;
1586ff6d951SJohn Birrell int n, err;
1596ff6d951SJohn Birrell
1606ff6d951SJohn Birrell dtrace_program_info(dtp, pgp, pip);
1616ff6d951SJohn Birrell
1626ff6d951SJohn Birrell if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL)
1636ff6d951SJohn Birrell return (-1);
1646ff6d951SJohn Birrell
165df5c121dSJohn Birrell args.dof = dof;
166df5c121dSJohn Birrell args.n_matched = 0;
167df5c121dSJohn Birrell n = dt_ioctl(dtp, DTRACEIOC_ENABLE, &args);
1686ff6d951SJohn Birrell dtrace_dof_destroy(dtp, dof);
1696ff6d951SJohn Birrell
1706ff6d951SJohn Birrell if (n == -1) {
1716ff6d951SJohn Birrell switch (errno) {
1726ff6d951SJohn Birrell case EINVAL:
1736ff6d951SJohn Birrell err = EDT_DIFINVAL;
1746ff6d951SJohn Birrell break;
1756ff6d951SJohn Birrell case EFAULT:
1766ff6d951SJohn Birrell err = EDT_DIFFAULT;
1776ff6d951SJohn Birrell break;
1786ff6d951SJohn Birrell case E2BIG:
1796ff6d951SJohn Birrell err = EDT_DIFSIZE;
1806ff6d951SJohn Birrell break;
1811670a1c2SRui Paulo case EBUSY:
1821670a1c2SRui Paulo err = EDT_ENABLING_ERR;
1831670a1c2SRui Paulo break;
1846ff6d951SJohn Birrell default:
1856ff6d951SJohn Birrell err = errno;
1866ff6d951SJohn Birrell }
1876ff6d951SJohn Birrell
1886ff6d951SJohn Birrell return (dt_set_errno(dtp, err));
1896ff6d951SJohn Birrell }
1906ff6d951SJohn Birrell
1916ff6d951SJohn Birrell if (pip != NULL)
192df5c121dSJohn Birrell pip->dpi_matches += args.n_matched;
1936ff6d951SJohn Birrell
1946ff6d951SJohn Birrell return (0);
1956ff6d951SJohn Birrell }
1966ff6d951SJohn Birrell
1976ff6d951SJohn Birrell static void
dt_ecbdesc_hold(dtrace_ecbdesc_t * edp)1986ff6d951SJohn Birrell dt_ecbdesc_hold(dtrace_ecbdesc_t *edp)
1996ff6d951SJohn Birrell {
2006ff6d951SJohn Birrell edp->dted_refcnt++;
2016ff6d951SJohn Birrell }
2026ff6d951SJohn Birrell
2036ff6d951SJohn Birrell void
dt_ecbdesc_release(dtrace_hdl_t * dtp,dtrace_ecbdesc_t * edp)2046ff6d951SJohn Birrell dt_ecbdesc_release(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
2056ff6d951SJohn Birrell {
2066ff6d951SJohn Birrell if (--edp->dted_refcnt > 0)
2076ff6d951SJohn Birrell return;
2086ff6d951SJohn Birrell
2096ff6d951SJohn Birrell dt_difo_free(dtp, edp->dted_pred.dtpdd_difo);
2106ff6d951SJohn Birrell assert(edp->dted_action == NULL);
2116ff6d951SJohn Birrell dt_free(dtp, edp);
2126ff6d951SJohn Birrell }
2136ff6d951SJohn Birrell
2146ff6d951SJohn Birrell dtrace_ecbdesc_t *
dt_ecbdesc_create(dtrace_hdl_t * dtp,const dtrace_probedesc_t * pdp)2156ff6d951SJohn Birrell dt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)
2166ff6d951SJohn Birrell {
2176ff6d951SJohn Birrell dtrace_ecbdesc_t *edp;
2186ff6d951SJohn Birrell
2196ff6d951SJohn Birrell if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) {
2206ff6d951SJohn Birrell (void) dt_set_errno(dtp, EDT_NOMEM);
2216ff6d951SJohn Birrell return (NULL);
2226ff6d951SJohn Birrell }
2236ff6d951SJohn Birrell
2246ff6d951SJohn Birrell edp->dted_probe = *pdp;
2256ff6d951SJohn Birrell dt_ecbdesc_hold(edp);
2266ff6d951SJohn Birrell return (edp);
2276ff6d951SJohn Birrell }
2286ff6d951SJohn Birrell
2296ff6d951SJohn Birrell dtrace_stmtdesc_t *
dtrace_stmt_create(dtrace_hdl_t * dtp,dtrace_ecbdesc_t * edp)2306ff6d951SJohn Birrell dtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
2316ff6d951SJohn Birrell {
2326ff6d951SJohn Birrell dtrace_stmtdesc_t *sdp;
2336ff6d951SJohn Birrell
2346ff6d951SJohn Birrell if ((sdp = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL)
2356ff6d951SJohn Birrell return (NULL);
2366ff6d951SJohn Birrell
2376ff6d951SJohn Birrell dt_ecbdesc_hold(edp);
2386ff6d951SJohn Birrell sdp->dtsd_ecbdesc = edp;
2396ff6d951SJohn Birrell sdp->dtsd_descattr = _dtrace_defattr;
2406ff6d951SJohn Birrell sdp->dtsd_stmtattr = _dtrace_defattr;
2416ff6d951SJohn Birrell
2426ff6d951SJohn Birrell return (sdp);
2436ff6d951SJohn Birrell }
2446ff6d951SJohn Birrell
2456ff6d951SJohn Birrell dtrace_actdesc_t *
dtrace_stmt_action(dtrace_hdl_t * dtp,dtrace_stmtdesc_t * sdp)2466ff6d951SJohn Birrell dtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
2476ff6d951SJohn Birrell {
2486ff6d951SJohn Birrell dtrace_actdesc_t *new;
2496ff6d951SJohn Birrell dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
2506ff6d951SJohn Birrell
2516ff6d951SJohn Birrell if ((new = dt_alloc(dtp, sizeof (dtrace_actdesc_t))) == NULL)
2526ff6d951SJohn Birrell return (NULL);
2536ff6d951SJohn Birrell
2546ff6d951SJohn Birrell if (sdp->dtsd_action_last != NULL) {
2556ff6d951SJohn Birrell assert(sdp->dtsd_action != NULL);
2566ff6d951SJohn Birrell assert(sdp->dtsd_action_last->dtad_next == NULL);
2576ff6d951SJohn Birrell sdp->dtsd_action_last->dtad_next = new;
2586ff6d951SJohn Birrell } else {
2596ff6d951SJohn Birrell dtrace_actdesc_t *ap = edp->dted_action;
2606ff6d951SJohn Birrell
2616ff6d951SJohn Birrell assert(sdp->dtsd_action == NULL);
2626ff6d951SJohn Birrell sdp->dtsd_action = new;
2636ff6d951SJohn Birrell
2646ff6d951SJohn Birrell while (ap != NULL && ap->dtad_next != NULL)
2656ff6d951SJohn Birrell ap = ap->dtad_next;
2666ff6d951SJohn Birrell
2676ff6d951SJohn Birrell if (ap == NULL)
2686ff6d951SJohn Birrell edp->dted_action = new;
2696ff6d951SJohn Birrell else
2706ff6d951SJohn Birrell ap->dtad_next = new;
2716ff6d951SJohn Birrell }
2726ff6d951SJohn Birrell
2736ff6d951SJohn Birrell sdp->dtsd_action_last = new;
2746ff6d951SJohn Birrell bzero(new, sizeof (dtrace_actdesc_t));
2756ff6d951SJohn Birrell new->dtad_uarg = (uintptr_t)sdp;
2766ff6d951SJohn Birrell
2776ff6d951SJohn Birrell return (new);
2786ff6d951SJohn Birrell }
2796ff6d951SJohn Birrell
2806ff6d951SJohn Birrell int
dtrace_stmt_add(dtrace_hdl_t * dtp,dtrace_prog_t * pgp,dtrace_stmtdesc_t * sdp)2816ff6d951SJohn Birrell dtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp)
2826ff6d951SJohn Birrell {
2836ff6d951SJohn Birrell dt_stmt_t *stp = dt_alloc(dtp, sizeof (dt_stmt_t));
2846ff6d951SJohn Birrell
2856ff6d951SJohn Birrell if (stp == NULL)
2866ff6d951SJohn Birrell return (-1); /* errno is set for us */
2876ff6d951SJohn Birrell
2886ff6d951SJohn Birrell dt_list_append(&pgp->dp_stmts, stp);
2896ff6d951SJohn Birrell stp->ds_desc = sdp;
2906ff6d951SJohn Birrell
2916ff6d951SJohn Birrell return (0);
2926ff6d951SJohn Birrell }
2936ff6d951SJohn Birrell
2946ff6d951SJohn Birrell int
dtrace_stmt_iter(dtrace_hdl_t * dtp,dtrace_prog_t * pgp,dtrace_stmt_f * func,void * data)2956ff6d951SJohn Birrell dtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
2966ff6d951SJohn Birrell dtrace_stmt_f *func, void *data)
2976ff6d951SJohn Birrell {
2986ff6d951SJohn Birrell dt_stmt_t *stp, *next;
2996ff6d951SJohn Birrell int status = 0;
3006ff6d951SJohn Birrell
3016ff6d951SJohn Birrell for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
3026ff6d951SJohn Birrell next = dt_list_next(stp);
3036ff6d951SJohn Birrell if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0)
3046ff6d951SJohn Birrell break;
3056ff6d951SJohn Birrell }
3066ff6d951SJohn Birrell
3076ff6d951SJohn Birrell return (status);
3086ff6d951SJohn Birrell }
3096ff6d951SJohn Birrell
3106ff6d951SJohn Birrell void
dtrace_stmt_destroy(dtrace_hdl_t * dtp,dtrace_stmtdesc_t * sdp)3116ff6d951SJohn Birrell dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
3126ff6d951SJohn Birrell {
3136ff6d951SJohn Birrell dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
3146ff6d951SJohn Birrell
3156ff6d951SJohn Birrell /*
3166ff6d951SJohn Birrell * We need to remove any actions that we have on this ECB, and
3176ff6d951SJohn Birrell * remove our hold on the ECB itself.
3186ff6d951SJohn Birrell */
3196ff6d951SJohn Birrell if (sdp->dtsd_action != NULL) {
3206ff6d951SJohn Birrell dtrace_actdesc_t *last = sdp->dtsd_action_last;
3216ff6d951SJohn Birrell dtrace_actdesc_t *ap, *next;
3226ff6d951SJohn Birrell
3236ff6d951SJohn Birrell assert(last != NULL);
3246ff6d951SJohn Birrell
3256ff6d951SJohn Birrell for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
3266ff6d951SJohn Birrell if (ap == sdp->dtsd_action)
3276ff6d951SJohn Birrell break;
3286ff6d951SJohn Birrell
3296ff6d951SJohn Birrell if (ap->dtad_next == sdp->dtsd_action)
3306ff6d951SJohn Birrell break;
3316ff6d951SJohn Birrell }
3326ff6d951SJohn Birrell
3336ff6d951SJohn Birrell assert(ap != NULL);
3346ff6d951SJohn Birrell
3356ff6d951SJohn Birrell if (ap == edp->dted_action)
3366ff6d951SJohn Birrell edp->dted_action = last->dtad_next;
3376ff6d951SJohn Birrell else
3386ff6d951SJohn Birrell ap->dtad_next = last->dtad_next;
3396ff6d951SJohn Birrell
3406ff6d951SJohn Birrell /*
3416ff6d951SJohn Birrell * We have now removed our action list from its ECB; we can
3426ff6d951SJohn Birrell * safely destroy the list.
3436ff6d951SJohn Birrell */
3446ff6d951SJohn Birrell last->dtad_next = NULL;
3456ff6d951SJohn Birrell
3466ff6d951SJohn Birrell for (ap = sdp->dtsd_action; ap != NULL; ap = next) {
3476ff6d951SJohn Birrell assert(ap->dtad_uarg == (uintptr_t)sdp);
3486ff6d951SJohn Birrell dt_difo_free(dtp, ap->dtad_difo);
3496ff6d951SJohn Birrell next = ap->dtad_next;
3506ff6d951SJohn Birrell dt_free(dtp, ap);
3516ff6d951SJohn Birrell }
3526ff6d951SJohn Birrell }
3536ff6d951SJohn Birrell
3546ff6d951SJohn Birrell if (sdp->dtsd_fmtdata != NULL)
3556ff6d951SJohn Birrell dt_printf_destroy(sdp->dtsd_fmtdata);
35654727873SPedro F. Giffuni dt_free(dtp, sdp->dtsd_strdata);
3576ff6d951SJohn Birrell
3586ff6d951SJohn Birrell dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc);
3596ff6d951SJohn Birrell dt_free(dtp, sdp);
3606ff6d951SJohn Birrell }
3616ff6d951SJohn Birrell
3626ff6d951SJohn Birrell typedef struct dt_header_info {
3636ff6d951SJohn Birrell dtrace_hdl_t *dthi_dtp; /* consumer handle */
3646ff6d951SJohn Birrell FILE *dthi_out; /* output file */
3656ff6d951SJohn Birrell char *dthi_pmname; /* provider macro name */
3666ff6d951SJohn Birrell char *dthi_pfname; /* provider function name */
3676ff6d951SJohn Birrell int dthi_empty; /* should we generate empty macros */
3686ff6d951SJohn Birrell } dt_header_info_t;
3696ff6d951SJohn Birrell
3706ff6d951SJohn Birrell static void
dt_header_fmt_macro(char * buf,const char * str)3716ff6d951SJohn Birrell dt_header_fmt_macro(char *buf, const char *str)
3726ff6d951SJohn Birrell {
3736ff6d951SJohn Birrell for (;;) {
3746ff6d951SJohn Birrell if (islower(*str)) {
3756ff6d951SJohn Birrell *buf++ = *str++ + 'A' - 'a';
3766ff6d951SJohn Birrell } else if (*str == '-') {
3776ff6d951SJohn Birrell *buf++ = '_';
3786ff6d951SJohn Birrell str++;
3796ff6d951SJohn Birrell } else if (*str == '.') {
3806ff6d951SJohn Birrell *buf++ = '_';
3816ff6d951SJohn Birrell str++;
3826ff6d951SJohn Birrell } else if ((*buf++ = *str++) == '\0') {
3836ff6d951SJohn Birrell break;
3846ff6d951SJohn Birrell }
3856ff6d951SJohn Birrell }
3866ff6d951SJohn Birrell }
3876ff6d951SJohn Birrell
3886ff6d951SJohn Birrell static void
dt_header_fmt_func(char * buf,const char * str)3896ff6d951SJohn Birrell dt_header_fmt_func(char *buf, const char *str)
3906ff6d951SJohn Birrell {
3916ff6d951SJohn Birrell for (;;) {
3926ff6d951SJohn Birrell if (*str == '-') {
3936ff6d951SJohn Birrell *buf++ = '_';
3946ff6d951SJohn Birrell *buf++ = '_';
3956ff6d951SJohn Birrell str++;
3966ff6d951SJohn Birrell } else if ((*buf++ = *str++) == '\0') {
3976ff6d951SJohn Birrell break;
3986ff6d951SJohn Birrell }
3996ff6d951SJohn Birrell }
4006ff6d951SJohn Birrell }
4016ff6d951SJohn Birrell
4026ff6d951SJohn Birrell /*ARGSUSED*/
4036ff6d951SJohn Birrell static int
dt_header_decl(dt_idhash_t * dhp,dt_ident_t * idp,void * data)4046ff6d951SJohn Birrell dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
4056ff6d951SJohn Birrell {
4066ff6d951SJohn Birrell dt_header_info_t *infop = data;
4076ff6d951SJohn Birrell dtrace_hdl_t *dtp = infop->dthi_dtp;
4086ff6d951SJohn Birrell dt_probe_t *prp = idp->di_data;
4096ff6d951SJohn Birrell dt_node_t *dnp;
4106ff6d951SJohn Birrell char buf[DT_TYPE_NAMELEN];
4116ff6d951SJohn Birrell char *fname;
4126ff6d951SJohn Birrell const char *p;
4136ff6d951SJohn Birrell int i;
4146ff6d951SJohn Birrell
4156ff6d951SJohn Birrell p = prp->pr_name;
4166ff6d951SJohn Birrell for (i = 0; (p = strchr(p, '-')) != NULL; i++)
4176ff6d951SJohn Birrell p++;
4186ff6d951SJohn Birrell
4196ff6d951SJohn Birrell fname = alloca(strlen(prp->pr_name) + 1 + i);
4206ff6d951SJohn Birrell dt_header_fmt_func(fname, prp->pr_name);
4216ff6d951SJohn Birrell
4226ff6d951SJohn Birrell if (fprintf(infop->dthi_out, "extern void __dtrace_%s___%s(",
4236ff6d951SJohn Birrell infop->dthi_pfname, fname) < 0)
4246ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
4256ff6d951SJohn Birrell
4266ff6d951SJohn Birrell for (dnp = prp->pr_nargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) {
4276ff6d951SJohn Birrell if (fprintf(infop->dthi_out, "%s",
4286ff6d951SJohn Birrell ctf_type_name(dnp->dn_ctfp, dnp->dn_type,
4296ff6d951SJohn Birrell buf, sizeof (buf))) < 0)
4306ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
4316ff6d951SJohn Birrell
4326ff6d951SJohn Birrell if (i + 1 != prp->pr_nargc &&
4336ff6d951SJohn Birrell fprintf(infop->dthi_out, ", ") < 0)
4346ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
4356ff6d951SJohn Birrell }
4366ff6d951SJohn Birrell
4376ff6d951SJohn Birrell if (i == 0 && fprintf(infop->dthi_out, "void") < 0)
4386ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
4396ff6d951SJohn Birrell
4406ff6d951SJohn Birrell if (fprintf(infop->dthi_out, ");\n") < 0)
4416ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
4426ff6d951SJohn Birrell
44356b35563SCraig Rodrigues if (fprintf(infop->dthi_out,
44456b35563SCraig Rodrigues "#ifndef\t__sparc\n"
44556b35563SCraig Rodrigues "extern int __dtraceenabled_%s___%s(void);\n"
44656b35563SCraig Rodrigues "#else\n"
44756b35563SCraig Rodrigues "extern int __dtraceenabled_%s___%s(long);\n"
44856b35563SCraig Rodrigues "#endif\n",
44956b35563SCraig Rodrigues infop->dthi_pfname, fname, infop->dthi_pfname, fname) < 0)
4506ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
4516ff6d951SJohn Birrell
4526ff6d951SJohn Birrell return (0);
4536ff6d951SJohn Birrell }
4546ff6d951SJohn Birrell
4556ff6d951SJohn Birrell /*ARGSUSED*/
4566ff6d951SJohn Birrell static int
dt_header_probe(dt_idhash_t * dhp,dt_ident_t * idp,void * data)4576ff6d951SJohn Birrell dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
4586ff6d951SJohn Birrell {
4596ff6d951SJohn Birrell dt_header_info_t *infop = data;
4606ff6d951SJohn Birrell dtrace_hdl_t *dtp = infop->dthi_dtp;
4616ff6d951SJohn Birrell dt_probe_t *prp = idp->di_data;
4626ff6d951SJohn Birrell char *mname, *fname;
4636ff6d951SJohn Birrell const char *p;
4646ff6d951SJohn Birrell int i;
4656ff6d951SJohn Birrell
4666ff6d951SJohn Birrell p = prp->pr_name;
4676ff6d951SJohn Birrell for (i = 0; (p = strchr(p, '-')) != NULL; i++)
4686ff6d951SJohn Birrell p++;
4696ff6d951SJohn Birrell
4706ff6d951SJohn Birrell mname = alloca(strlen(prp->pr_name) + 1);
4716ff6d951SJohn Birrell dt_header_fmt_macro(mname, prp->pr_name);
4726ff6d951SJohn Birrell
4736ff6d951SJohn Birrell fname = alloca(strlen(prp->pr_name) + 1 + i);
4746ff6d951SJohn Birrell dt_header_fmt_func(fname, prp->pr_name);
4756ff6d951SJohn Birrell
4766ff6d951SJohn Birrell if (fprintf(infop->dthi_out, "#define\t%s_%s(",
4776ff6d951SJohn Birrell infop->dthi_pmname, mname) < 0)
4786ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
4796ff6d951SJohn Birrell
4806ff6d951SJohn Birrell for (i = 0; i < prp->pr_nargc; i++) {
4816ff6d951SJohn Birrell if (fprintf(infop->dthi_out, "arg%d", i) < 0)
4826ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
4836ff6d951SJohn Birrell
4846ff6d951SJohn Birrell if (i + 1 != prp->pr_nargc &&
4856ff6d951SJohn Birrell fprintf(infop->dthi_out, ", ") < 0)
4866ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
4876ff6d951SJohn Birrell }
4886ff6d951SJohn Birrell
4896ff6d951SJohn Birrell if (!infop->dthi_empty) {
4906ff6d951SJohn Birrell if (fprintf(infop->dthi_out, ") \\\n\t") < 0)
4916ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
4926ff6d951SJohn Birrell
4936ff6d951SJohn Birrell if (fprintf(infop->dthi_out, "__dtrace_%s___%s(",
4946ff6d951SJohn Birrell infop->dthi_pfname, fname) < 0)
4956ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
4966ff6d951SJohn Birrell
4976ff6d951SJohn Birrell for (i = 0; i < prp->pr_nargc; i++) {
4986ff6d951SJohn Birrell if (fprintf(infop->dthi_out, "arg%d", i) < 0)
4996ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
5006ff6d951SJohn Birrell
5016ff6d951SJohn Birrell if (i + 1 != prp->pr_nargc &&
5026ff6d951SJohn Birrell fprintf(infop->dthi_out, ", ") < 0)
5036ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
5046ff6d951SJohn Birrell }
5056ff6d951SJohn Birrell }
5066ff6d951SJohn Birrell
5076ff6d951SJohn Birrell if (fprintf(infop->dthi_out, ")\n") < 0)
5086ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
5096ff6d951SJohn Birrell
5106ff6d951SJohn Birrell if (!infop->dthi_empty) {
51156b35563SCraig Rodrigues if (fprintf(infop->dthi_out,
51256b35563SCraig Rodrigues "#ifndef\t__sparc\n"
51356b35563SCraig Rodrigues "#define\t%s_%s_ENABLED() \\\n"
51456b35563SCraig Rodrigues "\t__dtraceenabled_%s___%s()\n"
51556b35563SCraig Rodrigues "#else\n"
51656b35563SCraig Rodrigues "#define\t%s_%s_ENABLED() \\\n"
51756b35563SCraig Rodrigues "\t__dtraceenabled_%s___%s(0)\n"
51856b35563SCraig Rodrigues "#endif\n",
51956b35563SCraig Rodrigues infop->dthi_pmname, mname,
52056b35563SCraig Rodrigues infop->dthi_pfname, fname,
52156b35563SCraig Rodrigues infop->dthi_pmname, mname,
5226ff6d951SJohn Birrell infop->dthi_pfname, fname) < 0)
5236ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
52456b35563SCraig Rodrigues
5256ff6d951SJohn Birrell } else {
5266ff6d951SJohn Birrell if (fprintf(infop->dthi_out, "#define\t%s_%s_ENABLED() (0)\n",
5276ff6d951SJohn Birrell infop->dthi_pmname, mname) < 0)
5286ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
5296ff6d951SJohn Birrell }
5306ff6d951SJohn Birrell
5316ff6d951SJohn Birrell return (0);
5326ff6d951SJohn Birrell }
5336ff6d951SJohn Birrell
5346ff6d951SJohn Birrell static int
dt_header_provider(dtrace_hdl_t * dtp,dt_provider_t * pvp,FILE * out)5356ff6d951SJohn Birrell dt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out)
5366ff6d951SJohn Birrell {
5376ff6d951SJohn Birrell dt_header_info_t info;
5386ff6d951SJohn Birrell const char *p;
5396ff6d951SJohn Birrell int i;
5406ff6d951SJohn Birrell
5416ff6d951SJohn Birrell if (pvp->pv_flags & DT_PROVIDER_IMPL)
5426ff6d951SJohn Birrell return (0);
5436ff6d951SJohn Birrell
5446ff6d951SJohn Birrell /*
5456ff6d951SJohn Birrell * Count the instances of the '-' character since we'll need to double
5466ff6d951SJohn Birrell * those up.
5476ff6d951SJohn Birrell */
5486ff6d951SJohn Birrell p = pvp->pv_desc.dtvd_name;
5496ff6d951SJohn Birrell for (i = 0; (p = strchr(p, '-')) != NULL; i++)
5506ff6d951SJohn Birrell p++;
5516ff6d951SJohn Birrell
5526ff6d951SJohn Birrell info.dthi_dtp = dtp;
5536ff6d951SJohn Birrell info.dthi_out = out;
5546ff6d951SJohn Birrell info.dthi_empty = 0;
5556ff6d951SJohn Birrell
5566ff6d951SJohn Birrell info.dthi_pmname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1);
5576ff6d951SJohn Birrell dt_header_fmt_macro(info.dthi_pmname, pvp->pv_desc.dtvd_name);
5586ff6d951SJohn Birrell
5596ff6d951SJohn Birrell info.dthi_pfname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1 + i);
5606ff6d951SJohn Birrell dt_header_fmt_func(info.dthi_pfname, pvp->pv_desc.dtvd_name);
5616ff6d951SJohn Birrell
5628f7264f0SRui Paulo #ifdef __FreeBSD__
5638f7264f0SRui Paulo if (fprintf(out, "#include <sys/sdt.h>\n\n") < 0)
5648f7264f0SRui Paulo return (dt_set_errno(dtp, errno));
5658f7264f0SRui Paulo #endif
5666ff6d951SJohn Birrell if (fprintf(out, "#if _DTRACE_VERSION\n\n") < 0)
5676ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
5686ff6d951SJohn Birrell
5696ff6d951SJohn Birrell if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
5706ff6d951SJohn Birrell return (-1); /* dt_errno is set for us */
5716ff6d951SJohn Birrell if (fprintf(out, "\n\n") < 0)
5726ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
5736ff6d951SJohn Birrell if (dt_idhash_iter(pvp->pv_probes, dt_header_decl, &info) != 0)
5746ff6d951SJohn Birrell return (-1); /* dt_errno is set for us */
5756ff6d951SJohn Birrell
5766ff6d951SJohn Birrell if (fprintf(out, "\n#else\n\n") < 0)
5776ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
5786ff6d951SJohn Birrell
5796ff6d951SJohn Birrell info.dthi_empty = 1;
5806ff6d951SJohn Birrell
5816ff6d951SJohn Birrell if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
5826ff6d951SJohn Birrell return (-1); /* dt_errno is set for us */
5836ff6d951SJohn Birrell
5846ff6d951SJohn Birrell if (fprintf(out, "\n#endif\n\n") < 0)
5856ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
5866ff6d951SJohn Birrell
5876ff6d951SJohn Birrell return (0);
5886ff6d951SJohn Birrell }
5896ff6d951SJohn Birrell
5906ff6d951SJohn Birrell int
dtrace_program_header(dtrace_hdl_t * dtp,FILE * out,const char * fname)5916ff6d951SJohn Birrell dtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname)
5926ff6d951SJohn Birrell {
5936ff6d951SJohn Birrell dt_provider_t *pvp;
5946ff6d951SJohn Birrell char *mfname, *p;
5956ff6d951SJohn Birrell
5966ff6d951SJohn Birrell if (fname != NULL) {
5976ff6d951SJohn Birrell if ((p = strrchr(fname, '/')) != NULL)
5986ff6d951SJohn Birrell fname = p + 1;
5996ff6d951SJohn Birrell
6006ff6d951SJohn Birrell mfname = alloca(strlen(fname) + 1);
6016ff6d951SJohn Birrell dt_header_fmt_macro(mfname, fname);
6026ff6d951SJohn Birrell if (fprintf(out, "#ifndef\t_%s\n#define\t_%s\n\n",
6036ff6d951SJohn Birrell mfname, mfname) < 0)
6046ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
6056ff6d951SJohn Birrell }
6066ff6d951SJohn Birrell
6076ff6d951SJohn Birrell if (fprintf(out, "#include <unistd.h>\n\n") < 0)
6086ff6d951SJohn Birrell return (-1);
6096ff6d951SJohn Birrell
6106ff6d951SJohn Birrell if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0)
6116ff6d951SJohn Birrell return (-1);
6126ff6d951SJohn Birrell
6136ff6d951SJohn Birrell for (pvp = dt_list_next(&dtp->dt_provlist);
6146ff6d951SJohn Birrell pvp != NULL; pvp = dt_list_next(pvp)) {
6156ff6d951SJohn Birrell if (dt_header_provider(dtp, pvp, out) != 0)
6166ff6d951SJohn Birrell return (-1); /* dt_errno is set for us */
6176ff6d951SJohn Birrell }
6186ff6d951SJohn Birrell
6196ff6d951SJohn Birrell if (fprintf(out, "\n#ifdef\t__cplusplus\n}\n#endif\n") < 0)
6206ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
6216ff6d951SJohn Birrell
6226ff6d951SJohn Birrell if (fname != NULL && fprintf(out, "\n#endif\t/* _%s */\n", mfname) < 0)
6236ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
6246ff6d951SJohn Birrell
6256ff6d951SJohn Birrell return (0);
6266ff6d951SJohn Birrell }
627