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