10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <unistd.h>
300Sstevel@tonic-gate #include <strings.h>
310Sstevel@tonic-gate #include <stdlib.h>
320Sstevel@tonic-gate #include <errno.h>
330Sstevel@tonic-gate #include <assert.h>
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include <dt_impl.h>
36*265Smws #include <dt_program.h>
370Sstevel@tonic-gate #include <dt_printf.h>
380Sstevel@tonic-gate 
390Sstevel@tonic-gate dtrace_prog_t *
40*265Smws dt_program_create(dtrace_hdl_t *dtp)
410Sstevel@tonic-gate {
42*265Smws 	dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t));
430Sstevel@tonic-gate 
440Sstevel@tonic-gate 	if (pgp != NULL)
450Sstevel@tonic-gate 		dt_list_append(&dtp->dt_programs, pgp);
460Sstevel@tonic-gate 	else
470Sstevel@tonic-gate 		(void) dt_set_errno(dtp, EDT_NOMEM);
480Sstevel@tonic-gate 
490Sstevel@tonic-gate 	return (pgp);
500Sstevel@tonic-gate }
510Sstevel@tonic-gate 
520Sstevel@tonic-gate void
53*265Smws dt_program_destroy(dtrace_hdl_t *dtp, dtrace_prog_t *pgp)
540Sstevel@tonic-gate {
550Sstevel@tonic-gate 	dt_stmt_t *stp, *next;
56*265Smws 	uint_t i;
570Sstevel@tonic-gate 
580Sstevel@tonic-gate 	for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
590Sstevel@tonic-gate 		next = dt_list_next(stp);
60*265Smws 		dtrace_stmt_destroy(dtp, stp->ds_desc);
61*265Smws 		dt_free(dtp, stp);
620Sstevel@tonic-gate 	}
630Sstevel@tonic-gate 
64*265Smws 	for (i = 0; i < pgp->dp_xrefslen; i++)
65*265Smws 		dt_free(dtp, pgp->dp_xrefs[i]);
66*265Smws 
67*265Smws 	dt_free(dtp, pgp->dp_xrefs);
680Sstevel@tonic-gate 	dt_list_delete(&dtp->dt_programs, pgp);
69*265Smws 	dt_free(dtp, pgp);
700Sstevel@tonic-gate }
710Sstevel@tonic-gate 
720Sstevel@tonic-gate /*ARGSUSED*/
730Sstevel@tonic-gate void
740Sstevel@tonic-gate dtrace_program_info(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
750Sstevel@tonic-gate     dtrace_proginfo_t *pip)
760Sstevel@tonic-gate {
770Sstevel@tonic-gate 	dt_stmt_t *stp;
780Sstevel@tonic-gate 	dtrace_actdesc_t *ap;
790Sstevel@tonic-gate 	dtrace_ecbdesc_t *last = NULL;
800Sstevel@tonic-gate 
810Sstevel@tonic-gate 	if (pip == NULL)
820Sstevel@tonic-gate 		return;
830Sstevel@tonic-gate 
840Sstevel@tonic-gate 	bzero(pip, sizeof (dtrace_proginfo_t));
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 	if (dt_list_next(&pgp->dp_stmts) != NULL) {
870Sstevel@tonic-gate 		pip->dpi_descattr = _dtrace_maxattr;
880Sstevel@tonic-gate 		pip->dpi_stmtattr = _dtrace_maxattr;
890Sstevel@tonic-gate 	} else {
900Sstevel@tonic-gate 		pip->dpi_descattr = _dtrace_defattr;
910Sstevel@tonic-gate 		pip->dpi_stmtattr = _dtrace_defattr;
920Sstevel@tonic-gate 	}
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 	for (stp = dt_list_next(&pgp->dp_stmts); stp; stp = dt_list_next(stp)) {
950Sstevel@tonic-gate 		dtrace_ecbdesc_t *edp = stp->ds_desc->dtsd_ecbdesc;
960Sstevel@tonic-gate 
970Sstevel@tonic-gate 		if (edp == last)
980Sstevel@tonic-gate 			continue;
990Sstevel@tonic-gate 		last = edp;
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 		pip->dpi_descattr =
1020Sstevel@tonic-gate 		    dt_attr_min(stp->ds_desc->dtsd_descattr, pip->dpi_descattr);
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 		pip->dpi_stmtattr =
1050Sstevel@tonic-gate 		    dt_attr_min(stp->ds_desc->dtsd_stmtattr, pip->dpi_stmtattr);
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate 		/*
1080Sstevel@tonic-gate 		 * If there aren't any actions, account for the fact that
1090Sstevel@tonic-gate 		 * recording the epid will generate a record.
1100Sstevel@tonic-gate 		 */
1110Sstevel@tonic-gate 		if (edp->dted_action == NULL)
1120Sstevel@tonic-gate 			pip->dpi_recgens++;
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 		for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
1150Sstevel@tonic-gate 			if (ap->dtad_kind == DTRACEACT_SPECULATE) {
1160Sstevel@tonic-gate 				pip->dpi_speculations++;
1170Sstevel@tonic-gate 				continue;
1180Sstevel@tonic-gate 			}
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 			if (DTRACEACT_ISAGG(ap->dtad_kind)) {
1210Sstevel@tonic-gate 				pip->dpi_recgens -= ap->dtad_arg;
1220Sstevel@tonic-gate 				pip->dpi_aggregates++;
1230Sstevel@tonic-gate 				continue;
1240Sstevel@tonic-gate 			}
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 			if (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind))
1270Sstevel@tonic-gate 				continue;
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 			if (ap->dtad_kind == DTRACEACT_DIFEXPR &&
1300Sstevel@tonic-gate 			    ap->dtad_difo->dtdo_rtype.dtdt_kind ==
1310Sstevel@tonic-gate 			    DIF_TYPE_CTF &&
1320Sstevel@tonic-gate 			    ap->dtad_difo->dtdo_rtype.dtdt_size == 0)
1330Sstevel@tonic-gate 				continue;
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 			pip->dpi_recgens++;
1360Sstevel@tonic-gate 		}
1370Sstevel@tonic-gate 	}
1380Sstevel@tonic-gate }
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate int
1410Sstevel@tonic-gate dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
1420Sstevel@tonic-gate     dtrace_proginfo_t *pip)
1430Sstevel@tonic-gate {
1440Sstevel@tonic-gate 	void *dof;
1450Sstevel@tonic-gate 	int n, err;
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	dtrace_program_info(dtp, pgp, pip);
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 	if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL)
1500Sstevel@tonic-gate 		return (-1);
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate 	n = dt_ioctl(dtp, DTRACEIOC_ENABLE, dof);
1530Sstevel@tonic-gate 	dtrace_dof_destroy(dtp, dof);
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	if (n == -1) {
1560Sstevel@tonic-gate 		switch (errno) {
1570Sstevel@tonic-gate 		case EINVAL:
1580Sstevel@tonic-gate 			err = EDT_DIFINVAL;
1590Sstevel@tonic-gate 			break;
1600Sstevel@tonic-gate 		case EFAULT:
1610Sstevel@tonic-gate 			err = EDT_DIFFAULT;
1620Sstevel@tonic-gate 			break;
1630Sstevel@tonic-gate 		case E2BIG:
1640Sstevel@tonic-gate 			err = EDT_DIFSIZE;
1650Sstevel@tonic-gate 			break;
1660Sstevel@tonic-gate 		default:
1670Sstevel@tonic-gate 			err = errno;
1680Sstevel@tonic-gate 		}
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 		return (dt_set_errno(dtp, err));
1710Sstevel@tonic-gate 	}
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	if (pip != NULL)
1740Sstevel@tonic-gate 		pip->dpi_matches += n;
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	return (0);
1770Sstevel@tonic-gate }
1780Sstevel@tonic-gate 
179*265Smws static void
180*265Smws dt_ecbdesc_hold(dtrace_ecbdesc_t *edp)
1810Sstevel@tonic-gate {
1820Sstevel@tonic-gate 	edp->dted_refcnt++;
1830Sstevel@tonic-gate }
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate void
186*265Smws dt_ecbdesc_release(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
1870Sstevel@tonic-gate {
1880Sstevel@tonic-gate 	if (--edp->dted_refcnt > 0)
1890Sstevel@tonic-gate 		return;
1900Sstevel@tonic-gate 
191*265Smws 	dt_difo_free(dtp, edp->dted_pred.dtpdd_difo);
1920Sstevel@tonic-gate 	assert(edp->dted_action == NULL);
193*265Smws 	dt_free(dtp, edp);
1940Sstevel@tonic-gate }
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate dtrace_ecbdesc_t *
197*265Smws dt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)
1980Sstevel@tonic-gate {
1990Sstevel@tonic-gate 	dtrace_ecbdesc_t *edp;
2000Sstevel@tonic-gate 
201*265Smws 	if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) {
2020Sstevel@tonic-gate 		(void) dt_set_errno(dtp, EDT_NOMEM);
2030Sstevel@tonic-gate 		return (NULL);
2040Sstevel@tonic-gate 	}
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	edp->dted_probe = *pdp;
207*265Smws 	dt_ecbdesc_hold(edp);
2080Sstevel@tonic-gate 	return (edp);
2090Sstevel@tonic-gate }
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate dtrace_stmtdesc_t *
2120Sstevel@tonic-gate dtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
2130Sstevel@tonic-gate {
2140Sstevel@tonic-gate 	dtrace_stmtdesc_t *sdp;
2150Sstevel@tonic-gate 
216*265Smws 	if ((sdp = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL)
2170Sstevel@tonic-gate 		return (NULL);
2180Sstevel@tonic-gate 
219*265Smws 	dt_ecbdesc_hold(edp);
2200Sstevel@tonic-gate 	sdp->dtsd_ecbdesc = edp;
2210Sstevel@tonic-gate 	sdp->dtsd_descattr = _dtrace_defattr;
2220Sstevel@tonic-gate 	sdp->dtsd_stmtattr = _dtrace_defattr;
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	return (sdp);
2250Sstevel@tonic-gate }
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate dtrace_actdesc_t *
2280Sstevel@tonic-gate dtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
2290Sstevel@tonic-gate {
2300Sstevel@tonic-gate 	dtrace_actdesc_t *new;
2310Sstevel@tonic-gate 	dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
2320Sstevel@tonic-gate 
233*265Smws 	if ((new = dt_alloc(dtp, sizeof (dtrace_actdesc_t))) == NULL)
2340Sstevel@tonic-gate 		return (NULL);
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 	if (sdp->dtsd_action_last != NULL) {
2370Sstevel@tonic-gate 		assert(sdp->dtsd_action != NULL);
2380Sstevel@tonic-gate 		assert(sdp->dtsd_action_last->dtad_next == NULL);
2390Sstevel@tonic-gate 		sdp->dtsd_action_last->dtad_next = new;
2400Sstevel@tonic-gate 	} else {
2410Sstevel@tonic-gate 		dtrace_actdesc_t *ap = edp->dted_action;
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 		assert(sdp->dtsd_action == NULL);
2440Sstevel@tonic-gate 		sdp->dtsd_action = new;
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 		while (ap != NULL && ap->dtad_next != NULL)
2470Sstevel@tonic-gate 			ap = ap->dtad_next;
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 		if (ap == NULL)
2500Sstevel@tonic-gate 			edp->dted_action = new;
2510Sstevel@tonic-gate 		else
2520Sstevel@tonic-gate 			ap->dtad_next = new;
2530Sstevel@tonic-gate 	}
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 	sdp->dtsd_action_last = new;
2560Sstevel@tonic-gate 	bzero(new, sizeof (dtrace_actdesc_t));
2570Sstevel@tonic-gate 	new->dtad_uarg = (uintptr_t)sdp;
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 	return (new);
2600Sstevel@tonic-gate }
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate int
2630Sstevel@tonic-gate dtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp)
2640Sstevel@tonic-gate {
265*265Smws 	dt_stmt_t *stp = dt_alloc(dtp, sizeof (dt_stmt_t));
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	if (stp == NULL)
268*265Smws 		return (-1); /* errno is set for us */
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 	dt_list_append(&pgp->dp_stmts, stp);
2710Sstevel@tonic-gate 	stp->ds_desc = sdp;
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	return (0);
2740Sstevel@tonic-gate }
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate int
2770Sstevel@tonic-gate dtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
2780Sstevel@tonic-gate     dtrace_stmt_f *func, void *data)
2790Sstevel@tonic-gate {
2800Sstevel@tonic-gate 	dt_stmt_t *stp, *next;
2810Sstevel@tonic-gate 	int status = 0;
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
2840Sstevel@tonic-gate 		next = dt_list_next(stp);
2850Sstevel@tonic-gate 		if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0)
2860Sstevel@tonic-gate 			break;
2870Sstevel@tonic-gate 	}
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	return (status);
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate void
293*265Smws dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
2940Sstevel@tonic-gate {
2950Sstevel@tonic-gate 	dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	/*
2980Sstevel@tonic-gate 	 * We need to remove any actions that we have on this ECB, and
2990Sstevel@tonic-gate 	 * remove our hold on the ECB itself.
3000Sstevel@tonic-gate 	 */
3010Sstevel@tonic-gate 	if (sdp->dtsd_action != NULL) {
3020Sstevel@tonic-gate 		dtrace_actdesc_t *last = sdp->dtsd_action_last;
3030Sstevel@tonic-gate 		dtrace_actdesc_t *ap, *next;
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 		assert(last != NULL);
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 		for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
3080Sstevel@tonic-gate 			if (ap == sdp->dtsd_action)
3090Sstevel@tonic-gate 				break;
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 			if (ap->dtad_next == sdp->dtsd_action)
3120Sstevel@tonic-gate 				break;
3130Sstevel@tonic-gate 		}
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 		assert(ap != NULL);
3160Sstevel@tonic-gate 
317*265Smws 		if (ap == edp->dted_action)
3180Sstevel@tonic-gate 			edp->dted_action = last->dtad_next;
319*265Smws 		else
3200Sstevel@tonic-gate 			ap->dtad_next = last->dtad_next;
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 		/*
3230Sstevel@tonic-gate 		 * We have now removed our action list from its ECB; we can
3240Sstevel@tonic-gate 		 * safely destroy the list.
3250Sstevel@tonic-gate 		 */
3260Sstevel@tonic-gate 		last->dtad_next = NULL;
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 		for (ap = sdp->dtsd_action; ap != NULL; ap = next) {
3290Sstevel@tonic-gate 			assert(ap->dtad_uarg == (uintptr_t)sdp);
330*265Smws 			dt_difo_free(dtp, ap->dtad_difo);
3310Sstevel@tonic-gate 			next = ap->dtad_next;
332*265Smws 			dt_free(dtp, ap);
3330Sstevel@tonic-gate 		}
3340Sstevel@tonic-gate 	}
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	if (sdp->dtsd_fmtdata != NULL)
3370Sstevel@tonic-gate 		dt_printf_destroy(sdp->dtsd_fmtdata);
3380Sstevel@tonic-gate 
339*265Smws 	dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc);
340*265Smws 	dt_free(dtp, sdp);
3410Sstevel@tonic-gate }
342