xref: /freebsd-src/cddl/contrib/opensolaris/lib/libdtrace/common/dt_program.c (revision 98e0ffaefb0f241cda3a72395d3be04192ae0d47)
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