xref: /illumos-gate/usr/src/lib/libdtrace/common/dt_program.c (revision 900524f30cbbebc670e146a87587f355b9f633ee)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
22*900524f3Sahl 
237c478bd9Sstevel@tonic-gate /*
24*900524f3Sahl  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
257c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <unistd.h>
317c478bd9Sstevel@tonic-gate #include <strings.h>
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
337c478bd9Sstevel@tonic-gate #include <errno.h>
347c478bd9Sstevel@tonic-gate #include <assert.h>
35*900524f3Sahl #include <ctype.h>
36*900524f3Sahl #include <alloca.h>
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include <dt_impl.h>
391a7c1b72Smws #include <dt_program.h>
407c478bd9Sstevel@tonic-gate #include <dt_printf.h>
41*900524f3Sahl #include <dt_provider.h>
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate dtrace_prog_t *
441a7c1b72Smws dt_program_create(dtrace_hdl_t *dtp)
457c478bd9Sstevel@tonic-gate {
461a7c1b72Smws 	dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t));
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate 	if (pgp != NULL)
497c478bd9Sstevel@tonic-gate 		dt_list_append(&dtp->dt_programs, pgp);
507c478bd9Sstevel@tonic-gate 	else
517c478bd9Sstevel@tonic-gate 		(void) dt_set_errno(dtp, EDT_NOMEM);
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate 	return (pgp);
547c478bd9Sstevel@tonic-gate }
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate void
571a7c1b72Smws dt_program_destroy(dtrace_hdl_t *dtp, dtrace_prog_t *pgp)
587c478bd9Sstevel@tonic-gate {
597c478bd9Sstevel@tonic-gate 	dt_stmt_t *stp, *next;
601a7c1b72Smws 	uint_t i;
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate 	for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
637c478bd9Sstevel@tonic-gate 		next = dt_list_next(stp);
641a7c1b72Smws 		dtrace_stmt_destroy(dtp, stp->ds_desc);
651a7c1b72Smws 		dt_free(dtp, stp);
667c478bd9Sstevel@tonic-gate 	}
677c478bd9Sstevel@tonic-gate 
681a7c1b72Smws 	for (i = 0; i < pgp->dp_xrefslen; i++)
691a7c1b72Smws 		dt_free(dtp, pgp->dp_xrefs[i]);
701a7c1b72Smws 
711a7c1b72Smws 	dt_free(dtp, pgp->dp_xrefs);
727c478bd9Sstevel@tonic-gate 	dt_list_delete(&dtp->dt_programs, pgp);
731a7c1b72Smws 	dt_free(dtp, pgp);
747c478bd9Sstevel@tonic-gate }
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate /*ARGSUSED*/
777c478bd9Sstevel@tonic-gate void
787c478bd9Sstevel@tonic-gate dtrace_program_info(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
797c478bd9Sstevel@tonic-gate     dtrace_proginfo_t *pip)
807c478bd9Sstevel@tonic-gate {
817c478bd9Sstevel@tonic-gate 	dt_stmt_t *stp;
827c478bd9Sstevel@tonic-gate 	dtrace_actdesc_t *ap;
837c478bd9Sstevel@tonic-gate 	dtrace_ecbdesc_t *last = NULL;
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	if (pip == NULL)
867c478bd9Sstevel@tonic-gate 		return;
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 	bzero(pip, sizeof (dtrace_proginfo_t));
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 	if (dt_list_next(&pgp->dp_stmts) != NULL) {
917c478bd9Sstevel@tonic-gate 		pip->dpi_descattr = _dtrace_maxattr;
927c478bd9Sstevel@tonic-gate 		pip->dpi_stmtattr = _dtrace_maxattr;
937c478bd9Sstevel@tonic-gate 	} else {
947c478bd9Sstevel@tonic-gate 		pip->dpi_descattr = _dtrace_defattr;
957c478bd9Sstevel@tonic-gate 		pip->dpi_stmtattr = _dtrace_defattr;
967c478bd9Sstevel@tonic-gate 	}
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	for (stp = dt_list_next(&pgp->dp_stmts); stp; stp = dt_list_next(stp)) {
997c478bd9Sstevel@tonic-gate 		dtrace_ecbdesc_t *edp = stp->ds_desc->dtsd_ecbdesc;
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 		if (edp == last)
1027c478bd9Sstevel@tonic-gate 			continue;
1037c478bd9Sstevel@tonic-gate 		last = edp;
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 		pip->dpi_descattr =
1067c478bd9Sstevel@tonic-gate 		    dt_attr_min(stp->ds_desc->dtsd_descattr, pip->dpi_descattr);
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 		pip->dpi_stmtattr =
1097c478bd9Sstevel@tonic-gate 		    dt_attr_min(stp->ds_desc->dtsd_stmtattr, pip->dpi_stmtattr);
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 		/*
1127c478bd9Sstevel@tonic-gate 		 * If there aren't any actions, account for the fact that
1137c478bd9Sstevel@tonic-gate 		 * recording the epid will generate a record.
1147c478bd9Sstevel@tonic-gate 		 */
1157c478bd9Sstevel@tonic-gate 		if (edp->dted_action == NULL)
1167c478bd9Sstevel@tonic-gate 			pip->dpi_recgens++;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 		for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
1197c478bd9Sstevel@tonic-gate 			if (ap->dtad_kind == DTRACEACT_SPECULATE) {
1207c478bd9Sstevel@tonic-gate 				pip->dpi_speculations++;
1217c478bd9Sstevel@tonic-gate 				continue;
1227c478bd9Sstevel@tonic-gate 			}
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 			if (DTRACEACT_ISAGG(ap->dtad_kind)) {
1257c478bd9Sstevel@tonic-gate 				pip->dpi_recgens -= ap->dtad_arg;
1267c478bd9Sstevel@tonic-gate 				pip->dpi_aggregates++;
1277c478bd9Sstevel@tonic-gate 				continue;
1287c478bd9Sstevel@tonic-gate 			}
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 			if (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind))
1317c478bd9Sstevel@tonic-gate 				continue;
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 			if (ap->dtad_kind == DTRACEACT_DIFEXPR &&
1347c478bd9Sstevel@tonic-gate 			    ap->dtad_difo->dtdo_rtype.dtdt_kind ==
1357c478bd9Sstevel@tonic-gate 			    DIF_TYPE_CTF &&
1367c478bd9Sstevel@tonic-gate 			    ap->dtad_difo->dtdo_rtype.dtdt_size == 0)
1377c478bd9Sstevel@tonic-gate 				continue;
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 			pip->dpi_recgens++;
1407c478bd9Sstevel@tonic-gate 		}
1417c478bd9Sstevel@tonic-gate 	}
1427c478bd9Sstevel@tonic-gate }
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate int
1457c478bd9Sstevel@tonic-gate dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
1467c478bd9Sstevel@tonic-gate     dtrace_proginfo_t *pip)
1477c478bd9Sstevel@tonic-gate {
1487c478bd9Sstevel@tonic-gate 	void *dof;
1497c478bd9Sstevel@tonic-gate 	int n, err;
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	dtrace_program_info(dtp, pgp, pip);
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL)
1547c478bd9Sstevel@tonic-gate 		return (-1);
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	n = dt_ioctl(dtp, DTRACEIOC_ENABLE, dof);
1577c478bd9Sstevel@tonic-gate 	dtrace_dof_destroy(dtp, dof);
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	if (n == -1) {
1607c478bd9Sstevel@tonic-gate 		switch (errno) {
1617c478bd9Sstevel@tonic-gate 		case EINVAL:
1627c478bd9Sstevel@tonic-gate 			err = EDT_DIFINVAL;
1637c478bd9Sstevel@tonic-gate 			break;
1647c478bd9Sstevel@tonic-gate 		case EFAULT:
1657c478bd9Sstevel@tonic-gate 			err = EDT_DIFFAULT;
1667c478bd9Sstevel@tonic-gate 			break;
1677c478bd9Sstevel@tonic-gate 		case E2BIG:
1687c478bd9Sstevel@tonic-gate 			err = EDT_DIFSIZE;
1697c478bd9Sstevel@tonic-gate 			break;
1707c478bd9Sstevel@tonic-gate 		default:
1717c478bd9Sstevel@tonic-gate 			err = errno;
1727c478bd9Sstevel@tonic-gate 		}
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 		return (dt_set_errno(dtp, err));
1757c478bd9Sstevel@tonic-gate 	}
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	if (pip != NULL)
1787c478bd9Sstevel@tonic-gate 		pip->dpi_matches += n;
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	return (0);
1817c478bd9Sstevel@tonic-gate }
1827c478bd9Sstevel@tonic-gate 
1831a7c1b72Smws static void
1841a7c1b72Smws dt_ecbdesc_hold(dtrace_ecbdesc_t *edp)
1857c478bd9Sstevel@tonic-gate {
1867c478bd9Sstevel@tonic-gate 	edp->dted_refcnt++;
1877c478bd9Sstevel@tonic-gate }
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate void
1901a7c1b72Smws dt_ecbdesc_release(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
1917c478bd9Sstevel@tonic-gate {
1927c478bd9Sstevel@tonic-gate 	if (--edp->dted_refcnt > 0)
1937c478bd9Sstevel@tonic-gate 		return;
1947c478bd9Sstevel@tonic-gate 
1951a7c1b72Smws 	dt_difo_free(dtp, edp->dted_pred.dtpdd_difo);
1967c478bd9Sstevel@tonic-gate 	assert(edp->dted_action == NULL);
1971a7c1b72Smws 	dt_free(dtp, edp);
1987c478bd9Sstevel@tonic-gate }
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate dtrace_ecbdesc_t *
2011a7c1b72Smws dt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)
2027c478bd9Sstevel@tonic-gate {
2037c478bd9Sstevel@tonic-gate 	dtrace_ecbdesc_t *edp;
2047c478bd9Sstevel@tonic-gate 
2051a7c1b72Smws 	if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) {
2067c478bd9Sstevel@tonic-gate 		(void) dt_set_errno(dtp, EDT_NOMEM);
2077c478bd9Sstevel@tonic-gate 		return (NULL);
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	edp->dted_probe = *pdp;
2111a7c1b72Smws 	dt_ecbdesc_hold(edp);
2127c478bd9Sstevel@tonic-gate 	return (edp);
2137c478bd9Sstevel@tonic-gate }
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate dtrace_stmtdesc_t *
2167c478bd9Sstevel@tonic-gate dtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
2177c478bd9Sstevel@tonic-gate {
2187c478bd9Sstevel@tonic-gate 	dtrace_stmtdesc_t *sdp;
2197c478bd9Sstevel@tonic-gate 
2201a7c1b72Smws 	if ((sdp = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL)
2217c478bd9Sstevel@tonic-gate 		return (NULL);
2227c478bd9Sstevel@tonic-gate 
2231a7c1b72Smws 	dt_ecbdesc_hold(edp);
2247c478bd9Sstevel@tonic-gate 	sdp->dtsd_ecbdesc = edp;
2257c478bd9Sstevel@tonic-gate 	sdp->dtsd_descattr = _dtrace_defattr;
2267c478bd9Sstevel@tonic-gate 	sdp->dtsd_stmtattr = _dtrace_defattr;
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	return (sdp);
2297c478bd9Sstevel@tonic-gate }
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate dtrace_actdesc_t *
2327c478bd9Sstevel@tonic-gate dtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
2337c478bd9Sstevel@tonic-gate {
2347c478bd9Sstevel@tonic-gate 	dtrace_actdesc_t *new;
2357c478bd9Sstevel@tonic-gate 	dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
2367c478bd9Sstevel@tonic-gate 
2371a7c1b72Smws 	if ((new = dt_alloc(dtp, sizeof (dtrace_actdesc_t))) == NULL)
2387c478bd9Sstevel@tonic-gate 		return (NULL);
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	if (sdp->dtsd_action_last != NULL) {
2417c478bd9Sstevel@tonic-gate 		assert(sdp->dtsd_action != NULL);
2427c478bd9Sstevel@tonic-gate 		assert(sdp->dtsd_action_last->dtad_next == NULL);
2437c478bd9Sstevel@tonic-gate 		sdp->dtsd_action_last->dtad_next = new;
2447c478bd9Sstevel@tonic-gate 	} else {
2457c478bd9Sstevel@tonic-gate 		dtrace_actdesc_t *ap = edp->dted_action;
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 		assert(sdp->dtsd_action == NULL);
2487c478bd9Sstevel@tonic-gate 		sdp->dtsd_action = new;
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 		while (ap != NULL && ap->dtad_next != NULL)
2517c478bd9Sstevel@tonic-gate 			ap = ap->dtad_next;
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 		if (ap == NULL)
2547c478bd9Sstevel@tonic-gate 			edp->dted_action = new;
2557c478bd9Sstevel@tonic-gate 		else
2567c478bd9Sstevel@tonic-gate 			ap->dtad_next = new;
2577c478bd9Sstevel@tonic-gate 	}
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 	sdp->dtsd_action_last = new;
2607c478bd9Sstevel@tonic-gate 	bzero(new, sizeof (dtrace_actdesc_t));
2617c478bd9Sstevel@tonic-gate 	new->dtad_uarg = (uintptr_t)sdp;
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	return (new);
2647c478bd9Sstevel@tonic-gate }
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate int
2677c478bd9Sstevel@tonic-gate dtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp)
2687c478bd9Sstevel@tonic-gate {
2691a7c1b72Smws 	dt_stmt_t *stp = dt_alloc(dtp, sizeof (dt_stmt_t));
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	if (stp == NULL)
2721a7c1b72Smws 		return (-1); /* errno is set for us */
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	dt_list_append(&pgp->dp_stmts, stp);
2757c478bd9Sstevel@tonic-gate 	stp->ds_desc = sdp;
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	return (0);
2787c478bd9Sstevel@tonic-gate }
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate int
2817c478bd9Sstevel@tonic-gate dtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
2827c478bd9Sstevel@tonic-gate     dtrace_stmt_f *func, void *data)
2837c478bd9Sstevel@tonic-gate {
2847c478bd9Sstevel@tonic-gate 	dt_stmt_t *stp, *next;
2857c478bd9Sstevel@tonic-gate 	int status = 0;
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
2887c478bd9Sstevel@tonic-gate 		next = dt_list_next(stp);
2897c478bd9Sstevel@tonic-gate 		if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0)
2907c478bd9Sstevel@tonic-gate 			break;
2917c478bd9Sstevel@tonic-gate 	}
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	return (status);
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate void
2971a7c1b72Smws dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
2987c478bd9Sstevel@tonic-gate {
2997c478bd9Sstevel@tonic-gate 	dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	/*
3027c478bd9Sstevel@tonic-gate 	 * We need to remove any actions that we have on this ECB, and
3037c478bd9Sstevel@tonic-gate 	 * remove our hold on the ECB itself.
3047c478bd9Sstevel@tonic-gate 	 */
3057c478bd9Sstevel@tonic-gate 	if (sdp->dtsd_action != NULL) {
3067c478bd9Sstevel@tonic-gate 		dtrace_actdesc_t *last = sdp->dtsd_action_last;
3077c478bd9Sstevel@tonic-gate 		dtrace_actdesc_t *ap, *next;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 		assert(last != NULL);
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 		for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
3127c478bd9Sstevel@tonic-gate 			if (ap == sdp->dtsd_action)
3137c478bd9Sstevel@tonic-gate 				break;
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 			if (ap->dtad_next == sdp->dtsd_action)
3167c478bd9Sstevel@tonic-gate 				break;
3177c478bd9Sstevel@tonic-gate 		}
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 		assert(ap != NULL);
3207c478bd9Sstevel@tonic-gate 
3211a7c1b72Smws 		if (ap == edp->dted_action)
3227c478bd9Sstevel@tonic-gate 			edp->dted_action = last->dtad_next;
3231a7c1b72Smws 		else
3247c478bd9Sstevel@tonic-gate 			ap->dtad_next = last->dtad_next;
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 		/*
3277c478bd9Sstevel@tonic-gate 		 * We have now removed our action list from its ECB; we can
3287c478bd9Sstevel@tonic-gate 		 * safely destroy the list.
3297c478bd9Sstevel@tonic-gate 		 */
3307c478bd9Sstevel@tonic-gate 		last->dtad_next = NULL;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 		for (ap = sdp->dtsd_action; ap != NULL; ap = next) {
3337c478bd9Sstevel@tonic-gate 			assert(ap->dtad_uarg == (uintptr_t)sdp);
3341a7c1b72Smws 			dt_difo_free(dtp, ap->dtad_difo);
3357c478bd9Sstevel@tonic-gate 			next = ap->dtad_next;
3361a7c1b72Smws 			dt_free(dtp, ap);
3377c478bd9Sstevel@tonic-gate 		}
3387c478bd9Sstevel@tonic-gate 	}
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	if (sdp->dtsd_fmtdata != NULL)
3417c478bd9Sstevel@tonic-gate 		dt_printf_destroy(sdp->dtsd_fmtdata);
3427c478bd9Sstevel@tonic-gate 
3431a7c1b72Smws 	dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc);
3441a7c1b72Smws 	dt_free(dtp, sdp);
3457c478bd9Sstevel@tonic-gate }
346*900524f3Sahl 
347*900524f3Sahl typedef struct dt_header_info {
348*900524f3Sahl 	dtrace_hdl_t *dthi_dtp;	/* consumer handle */
349*900524f3Sahl 	FILE *dthi_out;		/* output file */
350*900524f3Sahl 	char *dthi_pmname;	/* provider macro name */
351*900524f3Sahl 	char *dthi_pfname;	/* provider function name */
352*900524f3Sahl } dt_header_info_t;
353*900524f3Sahl 
354*900524f3Sahl 
355*900524f3Sahl static void
356*900524f3Sahl dt_header_fmt_macro(char *buf, const char *str)
357*900524f3Sahl {
358*900524f3Sahl 	for (;;) {
359*900524f3Sahl 		if (islower(*str)) {
360*900524f3Sahl 			*buf++ = *str++ + 'A' - 'a';
361*900524f3Sahl 		} else if (*str == '-') {
362*900524f3Sahl 			*buf++ = '_';
363*900524f3Sahl 			str++;
364*900524f3Sahl 		} else if (*str == '.') {
365*900524f3Sahl 			*buf++ = '_';
366*900524f3Sahl 			str++;
367*900524f3Sahl 		} else if ((*buf++ = *str++) == '\0') {
368*900524f3Sahl 			break;
369*900524f3Sahl 		}
370*900524f3Sahl 	}
371*900524f3Sahl }
372*900524f3Sahl 
373*900524f3Sahl static void
374*900524f3Sahl dt_header_fmt_func(char *buf, const char *str)
375*900524f3Sahl {
376*900524f3Sahl 	for (;;) {
377*900524f3Sahl 		if (*str == '-') {
378*900524f3Sahl 			*buf++ = '_';
379*900524f3Sahl 			*buf++ = '_';
380*900524f3Sahl 			str++;
381*900524f3Sahl 		} else if ((*buf++ = *str++) == '\0') {
382*900524f3Sahl 			break;
383*900524f3Sahl 		}
384*900524f3Sahl 	}
385*900524f3Sahl }
386*900524f3Sahl 
387*900524f3Sahl /*ARGSUSED*/
388*900524f3Sahl static int
389*900524f3Sahl dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
390*900524f3Sahl {
391*900524f3Sahl 	dt_header_info_t *infop = data;
392*900524f3Sahl 	dtrace_hdl_t *dtp = infop->dthi_dtp;
393*900524f3Sahl 	dt_probe_t *prp = idp->di_data;
394*900524f3Sahl 	dt_node_t *dnp;
395*900524f3Sahl 	char buf[DT_TYPE_NAMELEN];
396*900524f3Sahl 	char *fname;
397*900524f3Sahl 	const char *p;
398*900524f3Sahl 	int i;
399*900524f3Sahl 
400*900524f3Sahl 	p = prp->pr_name;
401*900524f3Sahl 	for (i = 0; (p = strchr(p, '-')) != NULL; i++)
402*900524f3Sahl 		p++;
403*900524f3Sahl 
404*900524f3Sahl 	fname = alloca(strlen(prp->pr_name) + 1 + i);
405*900524f3Sahl 	dt_header_fmt_func(fname, prp->pr_name);
406*900524f3Sahl 
407*900524f3Sahl 	if (fprintf(infop->dthi_out, "extern void __dtrace_%s___%s(",
408*900524f3Sahl 	    infop->dthi_pfname, fname) < 0)
409*900524f3Sahl 		return (dt_set_errno(dtp, errno));
410*900524f3Sahl 
411*900524f3Sahl 	for (dnp = prp->pr_nargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) {
412*900524f3Sahl 		if (fprintf(infop->dthi_out, "%s",
413*900524f3Sahl 		    ctf_type_name(dnp->dn_ctfp, dnp->dn_type,
414*900524f3Sahl 		    buf, sizeof (buf))) < 0)
415*900524f3Sahl 			return (dt_set_errno(dtp, errno));
416*900524f3Sahl 
417*900524f3Sahl 		if (i + 1 != prp->pr_nargc &&
418*900524f3Sahl 		    fprintf(infop->dthi_out, ", ") < 0)
419*900524f3Sahl 			return (dt_set_errno(dtp, errno));
420*900524f3Sahl 	}
421*900524f3Sahl 
422*900524f3Sahl 	if (i == 0 && fprintf(infop->dthi_out, "void") < 0)
423*900524f3Sahl 		return (dt_set_errno(dtp, errno));
424*900524f3Sahl 
425*900524f3Sahl 	if (fprintf(infop->dthi_out, ");\n") < 0)
426*900524f3Sahl 		return (dt_set_errno(dtp, errno));
427*900524f3Sahl 
428*900524f3Sahl 	return (0);
429*900524f3Sahl }
430*900524f3Sahl 
431*900524f3Sahl /*ARGSUSED*/
432*900524f3Sahl static int
433*900524f3Sahl dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
434*900524f3Sahl {
435*900524f3Sahl 	dt_header_info_t *infop = data;
436*900524f3Sahl 	dtrace_hdl_t *dtp = infop->dthi_dtp;
437*900524f3Sahl 	dt_probe_t *prp = idp->di_data;
438*900524f3Sahl 	char *mname, *fname;
439*900524f3Sahl 	const char *p;
440*900524f3Sahl 	int i;
441*900524f3Sahl 
442*900524f3Sahl 	p = prp->pr_name;
443*900524f3Sahl 	for (i = 0; (p = strchr(p, '-')) != NULL; i++)
444*900524f3Sahl 		p++;
445*900524f3Sahl 
446*900524f3Sahl 	mname = alloca(strlen(prp->pr_name) + 1);
447*900524f3Sahl 	dt_header_fmt_macro(mname, prp->pr_name);
448*900524f3Sahl 
449*900524f3Sahl 	fname = alloca(strlen(prp->pr_name) + 1 + i);
450*900524f3Sahl 	dt_header_fmt_func(fname, prp->pr_name);
451*900524f3Sahl 
452*900524f3Sahl 	if (fprintf(infop->dthi_out, "#define\t%s_%s(",
453*900524f3Sahl 	    infop->dthi_pmname, mname) < 0)
454*900524f3Sahl 		return (dt_set_errno(dtp, errno));
455*900524f3Sahl 
456*900524f3Sahl 	for (i = 0; i < prp->pr_nargc; i++) {
457*900524f3Sahl 		if (fprintf(infop->dthi_out, "arg%d", i) < 0)
458*900524f3Sahl 			return (dt_set_errno(dtp, errno));
459*900524f3Sahl 
460*900524f3Sahl 		if (i + 1 != prp->pr_nargc &&
461*900524f3Sahl 		    fprintf(infop->dthi_out, ", ") < 0)
462*900524f3Sahl 			return (dt_set_errno(dtp, errno));
463*900524f3Sahl 	}
464*900524f3Sahl 
465*900524f3Sahl 	if (fprintf(infop->dthi_out, ") \\\n\t") < 0)
466*900524f3Sahl 		return (dt_set_errno(dtp, errno));
467*900524f3Sahl 
468*900524f3Sahl 	if (fprintf(infop->dthi_out, "__dtrace_%s___%s(",
469*900524f3Sahl 	    infop->dthi_pfname, fname) < 0)
470*900524f3Sahl 		return (dt_set_errno(dtp, errno));
471*900524f3Sahl 
472*900524f3Sahl 	for (i = 0; i < prp->pr_nargc; i++) {
473*900524f3Sahl 		if (fprintf(infop->dthi_out, "arg%d", i) < 0)
474*900524f3Sahl 			return (dt_set_errno(dtp, errno));
475*900524f3Sahl 
476*900524f3Sahl 		if (i + 1 != prp->pr_nargc &&
477*900524f3Sahl 		    fprintf(infop->dthi_out, ", ") < 0)
478*900524f3Sahl 			return (dt_set_errno(dtp, errno));
479*900524f3Sahl 	}
480*900524f3Sahl 
481*900524f3Sahl 	if (fprintf(infop->dthi_out, ")\n") < 0)
482*900524f3Sahl 		return (dt_set_errno(dtp, errno));
483*900524f3Sahl 
484*900524f3Sahl 	return (0);
485*900524f3Sahl }
486*900524f3Sahl 
487*900524f3Sahl static int
488*900524f3Sahl dt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out)
489*900524f3Sahl {
490*900524f3Sahl 	dt_header_info_t info;
491*900524f3Sahl 	const char *p;
492*900524f3Sahl 	int i;
493*900524f3Sahl 
494*900524f3Sahl 	if (pvp->pv_flags & DT_PROVIDER_IMPL)
495*900524f3Sahl 		return (0);
496*900524f3Sahl 
497*900524f3Sahl 	p = pvp->pv_desc.dtvd_name;
498*900524f3Sahl 	for (i = 0; (p = strchr(p, '-')) != NULL; i++)
499*900524f3Sahl 		p++;
500*900524f3Sahl 
501*900524f3Sahl 	info.dthi_dtp = dtp;
502*900524f3Sahl 	info.dthi_out = out;
503*900524f3Sahl 
504*900524f3Sahl 	info.dthi_pmname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1);
505*900524f3Sahl 	dt_header_fmt_macro(info.dthi_pmname, pvp->pv_desc.dtvd_name);
506*900524f3Sahl 
507*900524f3Sahl 	info.dthi_pfname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1 + i);
508*900524f3Sahl 	dt_header_fmt_func(info.dthi_pfname, pvp->pv_desc.dtvd_name);
509*900524f3Sahl 
510*900524f3Sahl 
511*900524f3Sahl 	if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
512*900524f3Sahl 		return (-1); /* dt_errno is set for us */
513*900524f3Sahl 	if (fprintf(out, "\n\n") < 0)
514*900524f3Sahl 		return (dt_set_errno(dtp, errno));
515*900524f3Sahl 	if (dt_idhash_iter(pvp->pv_probes, dt_header_decl, &info) != 0)
516*900524f3Sahl 		return (-1); /* dt_errno is set for us */
517*900524f3Sahl 
518*900524f3Sahl 	return (0);
519*900524f3Sahl }
520*900524f3Sahl 
521*900524f3Sahl int
522*900524f3Sahl dtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname)
523*900524f3Sahl {
524*900524f3Sahl 	dt_provider_t *pvp;
525*900524f3Sahl 	char *mfname, *p;
526*900524f3Sahl 
527*900524f3Sahl 	if (fname != NULL) {
528*900524f3Sahl 		if ((p = strrchr(fname, '/')) != NULL)
529*900524f3Sahl 			fname = p + 1;
530*900524f3Sahl 
531*900524f3Sahl 		mfname = alloca(strlen(fname) + 1);
532*900524f3Sahl 		dt_header_fmt_macro(mfname, fname);
533*900524f3Sahl 		if (fprintf(out, "#ifndef\t_%s\n#define\t_%s\n\n",
534*900524f3Sahl 		    mfname, mfname) < 0)
535*900524f3Sahl 			return (dt_set_errno(dtp, errno));
536*900524f3Sahl 	}
537*900524f3Sahl 
538*900524f3Sahl 	if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0)
539*900524f3Sahl 		return (-1);
540*900524f3Sahl 
541*900524f3Sahl 	for (pvp = dt_list_next(&dtp->dt_provlist);
542*900524f3Sahl 	    pvp != NULL; pvp = dt_list_next(pvp)) {
543*900524f3Sahl 		if (dt_header_provider(dtp, pvp, out) != 0)
544*900524f3Sahl 			return (-1); /* dt_errno is set for us */
545*900524f3Sahl 	}
546*900524f3Sahl 
547*900524f3Sahl 	if (fprintf(out, "\n#ifdef\t__cplusplus\n}\n#endif\n") < 0)
548*900524f3Sahl 		return (dt_set_errno(dtp, errno));
549*900524f3Sahl 
550*900524f3Sahl 	if (fname != NULL && fprintf(out, "\n#endif\t/* _%s */\n", mfname) < 0)
551*900524f3Sahl 		return (dt_set_errno(dtp, errno));
552*900524f3Sahl 
553*900524f3Sahl 	return (0);
554*900524f3Sahl }
555