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
51710Sahl  * Common Development and Distribution License (the "License").
61710Sahl  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
211399Sahl 
220Sstevel@tonic-gate /*
23*8803SJonathan.Haslam@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #include <unistd.h>
280Sstevel@tonic-gate #include <strings.h>
290Sstevel@tonic-gate #include <stdlib.h>
300Sstevel@tonic-gate #include <errno.h>
310Sstevel@tonic-gate #include <assert.h>
321399Sahl #include <ctype.h>
331399Sahl #include <alloca.h>
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include <dt_impl.h>
36265Smws #include <dt_program.h>
370Sstevel@tonic-gate #include <dt_printf.h>
381399Sahl #include <dt_provider.h>
390Sstevel@tonic-gate 
400Sstevel@tonic-gate dtrace_prog_t *
41265Smws dt_program_create(dtrace_hdl_t *dtp)
420Sstevel@tonic-gate {
43265Smws 	dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t));
440Sstevel@tonic-gate 
450Sstevel@tonic-gate 	if (pgp != NULL)
460Sstevel@tonic-gate 		dt_list_append(&dtp->dt_programs, pgp);
470Sstevel@tonic-gate 	else
480Sstevel@tonic-gate 		(void) dt_set_errno(dtp, EDT_NOMEM);
490Sstevel@tonic-gate 
501710Sahl 	/*
511710Sahl 	 * By default, programs start with DOF version 1 so that output files
521710Sahl 	 * containing DOF are backward compatible. If a program requires new
531710Sahl 	 * DOF features, the version is increased as needed.
541710Sahl 	 */
551710Sahl 	pgp->dp_dofversion = DOF_VERSION_1;
561710Sahl 
570Sstevel@tonic-gate 	return (pgp);
580Sstevel@tonic-gate }
590Sstevel@tonic-gate 
600Sstevel@tonic-gate void
61265Smws dt_program_destroy(dtrace_hdl_t *dtp, dtrace_prog_t *pgp)
620Sstevel@tonic-gate {
630Sstevel@tonic-gate 	dt_stmt_t *stp, *next;
64265Smws 	uint_t i;
650Sstevel@tonic-gate 
660Sstevel@tonic-gate 	for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
670Sstevel@tonic-gate 		next = dt_list_next(stp);
68265Smws 		dtrace_stmt_destroy(dtp, stp->ds_desc);
69265Smws 		dt_free(dtp, stp);
700Sstevel@tonic-gate 	}
710Sstevel@tonic-gate 
72265Smws 	for (i = 0; i < pgp->dp_xrefslen; i++)
73265Smws 		dt_free(dtp, pgp->dp_xrefs[i]);
74265Smws 
75265Smws 	dt_free(dtp, pgp->dp_xrefs);
760Sstevel@tonic-gate 	dt_list_delete(&dtp->dt_programs, pgp);
77265Smws 	dt_free(dtp, pgp);
780Sstevel@tonic-gate }
790Sstevel@tonic-gate 
800Sstevel@tonic-gate /*ARGSUSED*/
810Sstevel@tonic-gate void
820Sstevel@tonic-gate dtrace_program_info(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
830Sstevel@tonic-gate     dtrace_proginfo_t *pip)
840Sstevel@tonic-gate {
850Sstevel@tonic-gate 	dt_stmt_t *stp;
860Sstevel@tonic-gate 	dtrace_actdesc_t *ap;
870Sstevel@tonic-gate 	dtrace_ecbdesc_t *last = NULL;
880Sstevel@tonic-gate 
890Sstevel@tonic-gate 	if (pip == NULL)
900Sstevel@tonic-gate 		return;
910Sstevel@tonic-gate 
920Sstevel@tonic-gate 	bzero(pip, sizeof (dtrace_proginfo_t));
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 	if (dt_list_next(&pgp->dp_stmts) != NULL) {
950Sstevel@tonic-gate 		pip->dpi_descattr = _dtrace_maxattr;
960Sstevel@tonic-gate 		pip->dpi_stmtattr = _dtrace_maxattr;
970Sstevel@tonic-gate 	} else {
980Sstevel@tonic-gate 		pip->dpi_descattr = _dtrace_defattr;
990Sstevel@tonic-gate 		pip->dpi_stmtattr = _dtrace_defattr;
1000Sstevel@tonic-gate 	}
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate 	for (stp = dt_list_next(&pgp->dp_stmts); stp; stp = dt_list_next(stp)) {
1030Sstevel@tonic-gate 		dtrace_ecbdesc_t *edp = stp->ds_desc->dtsd_ecbdesc;
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate 		if (edp == last)
1060Sstevel@tonic-gate 			continue;
1070Sstevel@tonic-gate 		last = edp;
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 		pip->dpi_descattr =
1100Sstevel@tonic-gate 		    dt_attr_min(stp->ds_desc->dtsd_descattr, pip->dpi_descattr);
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 		pip->dpi_stmtattr =
1130Sstevel@tonic-gate 		    dt_attr_min(stp->ds_desc->dtsd_stmtattr, pip->dpi_stmtattr);
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 		/*
1160Sstevel@tonic-gate 		 * If there aren't any actions, account for the fact that
1170Sstevel@tonic-gate 		 * recording the epid will generate a record.
1180Sstevel@tonic-gate 		 */
1190Sstevel@tonic-gate 		if (edp->dted_action == NULL)
1200Sstevel@tonic-gate 			pip->dpi_recgens++;
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 		for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
1230Sstevel@tonic-gate 			if (ap->dtad_kind == DTRACEACT_SPECULATE) {
1240Sstevel@tonic-gate 				pip->dpi_speculations++;
1250Sstevel@tonic-gate 				continue;
1260Sstevel@tonic-gate 			}
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 			if (DTRACEACT_ISAGG(ap->dtad_kind)) {
1290Sstevel@tonic-gate 				pip->dpi_recgens -= ap->dtad_arg;
1300Sstevel@tonic-gate 				pip->dpi_aggregates++;
1310Sstevel@tonic-gate 				continue;
1320Sstevel@tonic-gate 			}
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 			if (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind))
1350Sstevel@tonic-gate 				continue;
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 			if (ap->dtad_kind == DTRACEACT_DIFEXPR &&
1380Sstevel@tonic-gate 			    ap->dtad_difo->dtdo_rtype.dtdt_kind ==
1390Sstevel@tonic-gate 			    DIF_TYPE_CTF &&
1400Sstevel@tonic-gate 			    ap->dtad_difo->dtdo_rtype.dtdt_size == 0)
1410Sstevel@tonic-gate 				continue;
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 			pip->dpi_recgens++;
1440Sstevel@tonic-gate 		}
1450Sstevel@tonic-gate 	}
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate int
1490Sstevel@tonic-gate dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
1500Sstevel@tonic-gate     dtrace_proginfo_t *pip)
1510Sstevel@tonic-gate {
1520Sstevel@tonic-gate 	void *dof;
1530Sstevel@tonic-gate 	int n, err;
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	dtrace_program_info(dtp, pgp, pip);
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 	if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL)
1580Sstevel@tonic-gate 		return (-1);
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	n = dt_ioctl(dtp, DTRACEIOC_ENABLE, dof);
1610Sstevel@tonic-gate 	dtrace_dof_destroy(dtp, dof);
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	if (n == -1) {
1640Sstevel@tonic-gate 		switch (errno) {
1650Sstevel@tonic-gate 		case EINVAL:
1660Sstevel@tonic-gate 			err = EDT_DIFINVAL;
1670Sstevel@tonic-gate 			break;
1680Sstevel@tonic-gate 		case EFAULT:
1690Sstevel@tonic-gate 			err = EDT_DIFFAULT;
1700Sstevel@tonic-gate 			break;
1710Sstevel@tonic-gate 		case E2BIG:
1720Sstevel@tonic-gate 			err = EDT_DIFSIZE;
1730Sstevel@tonic-gate 			break;
174*8803SJonathan.Haslam@Sun.COM 		case EBUSY:
175*8803SJonathan.Haslam@Sun.COM 			err = EDT_ENABLING_ERR;
176*8803SJonathan.Haslam@Sun.COM 			break;
1770Sstevel@tonic-gate 		default:
1780Sstevel@tonic-gate 			err = errno;
1790Sstevel@tonic-gate 		}
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 		return (dt_set_errno(dtp, err));
1820Sstevel@tonic-gate 	}
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 	if (pip != NULL)
1850Sstevel@tonic-gate 		pip->dpi_matches += n;
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate 	return (0);
1880Sstevel@tonic-gate }
1890Sstevel@tonic-gate 
190265Smws static void
191265Smws dt_ecbdesc_hold(dtrace_ecbdesc_t *edp)
1920Sstevel@tonic-gate {
1930Sstevel@tonic-gate 	edp->dted_refcnt++;
1940Sstevel@tonic-gate }
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate void
197265Smws dt_ecbdesc_release(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
1980Sstevel@tonic-gate {
1990Sstevel@tonic-gate 	if (--edp->dted_refcnt > 0)
2000Sstevel@tonic-gate 		return;
2010Sstevel@tonic-gate 
202265Smws 	dt_difo_free(dtp, edp->dted_pred.dtpdd_difo);
2030Sstevel@tonic-gate 	assert(edp->dted_action == NULL);
204265Smws 	dt_free(dtp, edp);
2050Sstevel@tonic-gate }
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate dtrace_ecbdesc_t *
208265Smws dt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)
2090Sstevel@tonic-gate {
2100Sstevel@tonic-gate 	dtrace_ecbdesc_t *edp;
2110Sstevel@tonic-gate 
212265Smws 	if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) {
2130Sstevel@tonic-gate 		(void) dt_set_errno(dtp, EDT_NOMEM);
2140Sstevel@tonic-gate 		return (NULL);
2150Sstevel@tonic-gate 	}
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	edp->dted_probe = *pdp;
218265Smws 	dt_ecbdesc_hold(edp);
2190Sstevel@tonic-gate 	return (edp);
2200Sstevel@tonic-gate }
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate dtrace_stmtdesc_t *
2230Sstevel@tonic-gate dtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
2240Sstevel@tonic-gate {
2250Sstevel@tonic-gate 	dtrace_stmtdesc_t *sdp;
2260Sstevel@tonic-gate 
227265Smws 	if ((sdp = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL)
2280Sstevel@tonic-gate 		return (NULL);
2290Sstevel@tonic-gate 
230265Smws 	dt_ecbdesc_hold(edp);
2310Sstevel@tonic-gate 	sdp->dtsd_ecbdesc = edp;
2320Sstevel@tonic-gate 	sdp->dtsd_descattr = _dtrace_defattr;
2330Sstevel@tonic-gate 	sdp->dtsd_stmtattr = _dtrace_defattr;
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	return (sdp);
2360Sstevel@tonic-gate }
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate dtrace_actdesc_t *
2390Sstevel@tonic-gate dtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
2400Sstevel@tonic-gate {
2410Sstevel@tonic-gate 	dtrace_actdesc_t *new;
2420Sstevel@tonic-gate 	dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
2430Sstevel@tonic-gate 
244265Smws 	if ((new = dt_alloc(dtp, sizeof (dtrace_actdesc_t))) == NULL)
2450Sstevel@tonic-gate 		return (NULL);
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 	if (sdp->dtsd_action_last != NULL) {
2480Sstevel@tonic-gate 		assert(sdp->dtsd_action != NULL);
2490Sstevel@tonic-gate 		assert(sdp->dtsd_action_last->dtad_next == NULL);
2500Sstevel@tonic-gate 		sdp->dtsd_action_last->dtad_next = new;
2510Sstevel@tonic-gate 	} else {
2520Sstevel@tonic-gate 		dtrace_actdesc_t *ap = edp->dted_action;
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 		assert(sdp->dtsd_action == NULL);
2550Sstevel@tonic-gate 		sdp->dtsd_action = new;
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 		while (ap != NULL && ap->dtad_next != NULL)
2580Sstevel@tonic-gate 			ap = ap->dtad_next;
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 		if (ap == NULL)
2610Sstevel@tonic-gate 			edp->dted_action = new;
2620Sstevel@tonic-gate 		else
2630Sstevel@tonic-gate 			ap->dtad_next = new;
2640Sstevel@tonic-gate 	}
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	sdp->dtsd_action_last = new;
2670Sstevel@tonic-gate 	bzero(new, sizeof (dtrace_actdesc_t));
2680Sstevel@tonic-gate 	new->dtad_uarg = (uintptr_t)sdp;
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 	return (new);
2710Sstevel@tonic-gate }
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate int
2740Sstevel@tonic-gate dtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp)
2750Sstevel@tonic-gate {
276265Smws 	dt_stmt_t *stp = dt_alloc(dtp, sizeof (dt_stmt_t));
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	if (stp == NULL)
279265Smws 		return (-1); /* errno is set for us */
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	dt_list_append(&pgp->dp_stmts, stp);
2820Sstevel@tonic-gate 	stp->ds_desc = sdp;
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	return (0);
2850Sstevel@tonic-gate }
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate int
2880Sstevel@tonic-gate dtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
2890Sstevel@tonic-gate     dtrace_stmt_f *func, void *data)
2900Sstevel@tonic-gate {
2910Sstevel@tonic-gate 	dt_stmt_t *stp, *next;
2920Sstevel@tonic-gate 	int status = 0;
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
2950Sstevel@tonic-gate 		next = dt_list_next(stp);
2960Sstevel@tonic-gate 		if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0)
2970Sstevel@tonic-gate 			break;
2980Sstevel@tonic-gate 	}
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	return (status);
3010Sstevel@tonic-gate }
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate void
304265Smws dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
3050Sstevel@tonic-gate {
3060Sstevel@tonic-gate 	dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	/*
3090Sstevel@tonic-gate 	 * We need to remove any actions that we have on this ECB, and
3100Sstevel@tonic-gate 	 * remove our hold on the ECB itself.
3110Sstevel@tonic-gate 	 */
3120Sstevel@tonic-gate 	if (sdp->dtsd_action != NULL) {
3130Sstevel@tonic-gate 		dtrace_actdesc_t *last = sdp->dtsd_action_last;
3140Sstevel@tonic-gate 		dtrace_actdesc_t *ap, *next;
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 		assert(last != NULL);
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 		for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
3190Sstevel@tonic-gate 			if (ap == sdp->dtsd_action)
3200Sstevel@tonic-gate 				break;
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 			if (ap->dtad_next == sdp->dtsd_action)
3230Sstevel@tonic-gate 				break;
3240Sstevel@tonic-gate 		}
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 		assert(ap != NULL);
3270Sstevel@tonic-gate 
328265Smws 		if (ap == edp->dted_action)
3290Sstevel@tonic-gate 			edp->dted_action = last->dtad_next;
330265Smws 		else
3310Sstevel@tonic-gate 			ap->dtad_next = last->dtad_next;
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 		/*
3340Sstevel@tonic-gate 		 * We have now removed our action list from its ECB; we can
3350Sstevel@tonic-gate 		 * safely destroy the list.
3360Sstevel@tonic-gate 		 */
3370Sstevel@tonic-gate 		last->dtad_next = NULL;
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 		for (ap = sdp->dtsd_action; ap != NULL; ap = next) {
3400Sstevel@tonic-gate 			assert(ap->dtad_uarg == (uintptr_t)sdp);
341265Smws 			dt_difo_free(dtp, ap->dtad_difo);
3420Sstevel@tonic-gate 			next = ap->dtad_next;
343265Smws 			dt_free(dtp, ap);
3440Sstevel@tonic-gate 		}
3450Sstevel@tonic-gate 	}
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 	if (sdp->dtsd_fmtdata != NULL)
3480Sstevel@tonic-gate 		dt_printf_destroy(sdp->dtsd_fmtdata);
3490Sstevel@tonic-gate 
350265Smws 	dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc);
351265Smws 	dt_free(dtp, sdp);
3520Sstevel@tonic-gate }
3531399Sahl 
3541399Sahl typedef struct dt_header_info {
3551399Sahl 	dtrace_hdl_t *dthi_dtp;	/* consumer handle */
3561399Sahl 	FILE *dthi_out;		/* output file */
3571399Sahl 	char *dthi_pmname;	/* provider macro name */
3581399Sahl 	char *dthi_pfname;	/* provider function name */
3592769Sahl 	int dthi_empty;		/* should we generate empty macros */
3601399Sahl } dt_header_info_t;
3611399Sahl 
3621399Sahl static void
3631399Sahl dt_header_fmt_macro(char *buf, const char *str)
3641399Sahl {
3651399Sahl 	for (;;) {
3661399Sahl 		if (islower(*str)) {
3671399Sahl 			*buf++ = *str++ + 'A' - 'a';
3681399Sahl 		} else if (*str == '-') {
3691399Sahl 			*buf++ = '_';
3701399Sahl 			str++;
3711399Sahl 		} else if (*str == '.') {
3721399Sahl 			*buf++ = '_';
3731399Sahl 			str++;
3741399Sahl 		} else if ((*buf++ = *str++) == '\0') {
3751399Sahl 			break;
3761399Sahl 		}
3771399Sahl 	}
3781399Sahl }
3791399Sahl 
3801399Sahl static void
3811399Sahl dt_header_fmt_func(char *buf, const char *str)
3821399Sahl {
3831399Sahl 	for (;;) {
3841399Sahl 		if (*str == '-') {
3851399Sahl 			*buf++ = '_';
3861399Sahl 			*buf++ = '_';
3871399Sahl 			str++;
3881399Sahl 		} else if ((*buf++ = *str++) == '\0') {
3891399Sahl 			break;
3901399Sahl 		}
3911399Sahl 	}
3921399Sahl }
3931399Sahl 
3941399Sahl /*ARGSUSED*/
3951399Sahl static int
3961399Sahl dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
3971399Sahl {
3981399Sahl 	dt_header_info_t *infop = data;
3991399Sahl 	dtrace_hdl_t *dtp = infop->dthi_dtp;
4001399Sahl 	dt_probe_t *prp = idp->di_data;
4011399Sahl 	dt_node_t *dnp;
4021399Sahl 	char buf[DT_TYPE_NAMELEN];
4031399Sahl 	char *fname;
4041399Sahl 	const char *p;
4051399Sahl 	int i;
4061399Sahl 
4071399Sahl 	p = prp->pr_name;
4081399Sahl 	for (i = 0; (p = strchr(p, '-')) != NULL; i++)
4091399Sahl 		p++;
4101399Sahl 
4111399Sahl 	fname = alloca(strlen(prp->pr_name) + 1 + i);
4121399Sahl 	dt_header_fmt_func(fname, prp->pr_name);
4131399Sahl 
4141399Sahl 	if (fprintf(infop->dthi_out, "extern void __dtrace_%s___%s(",
4151399Sahl 	    infop->dthi_pfname, fname) < 0)
4161399Sahl 		return (dt_set_errno(dtp, errno));
4171399Sahl 
4181399Sahl 	for (dnp = prp->pr_nargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) {
4191399Sahl 		if (fprintf(infop->dthi_out, "%s",
4201399Sahl 		    ctf_type_name(dnp->dn_ctfp, dnp->dn_type,
4211399Sahl 		    buf, sizeof (buf))) < 0)
4221399Sahl 			return (dt_set_errno(dtp, errno));
4231399Sahl 
4241399Sahl 		if (i + 1 != prp->pr_nargc &&
4251399Sahl 		    fprintf(infop->dthi_out, ", ") < 0)
4261399Sahl 			return (dt_set_errno(dtp, errno));
4271399Sahl 	}
4281399Sahl 
4291399Sahl 	if (i == 0 && fprintf(infop->dthi_out, "void") < 0)
4301399Sahl 		return (dt_set_errno(dtp, errno));
4311399Sahl 
4321399Sahl 	if (fprintf(infop->dthi_out, ");\n") < 0)
4331399Sahl 		return (dt_set_errno(dtp, errno));
4341399Sahl 
4356554Sahl 	if (fprintf(infop->dthi_out,
4366554Sahl 	    "#ifndef\t__sparc\n"
4376554Sahl 	    "extern int __dtraceenabled_%s___%s(void);\n"
4386554Sahl 	    "#else\n"
4396554Sahl 	    "extern int __dtraceenabled_%s___%s(long);\n"
4406554Sahl 	    "#endif\n",
4416554Sahl 	    infop->dthi_pfname, fname, infop->dthi_pfname, fname) < 0)
4421710Sahl 		return (dt_set_errno(dtp, errno));
4431710Sahl 
4441399Sahl 	return (0);
4451399Sahl }
4461399Sahl 
4471399Sahl /*ARGSUSED*/
4481399Sahl static int
4491399Sahl dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
4501399Sahl {
4511399Sahl 	dt_header_info_t *infop = data;
4521399Sahl 	dtrace_hdl_t *dtp = infop->dthi_dtp;
4531399Sahl 	dt_probe_t *prp = idp->di_data;
4541399Sahl 	char *mname, *fname;
4551399Sahl 	const char *p;
4561399Sahl 	int i;
4571399Sahl 
4581399Sahl 	p = prp->pr_name;
4591399Sahl 	for (i = 0; (p = strchr(p, '-')) != NULL; i++)
4601399Sahl 		p++;
4611399Sahl 
4621399Sahl 	mname = alloca(strlen(prp->pr_name) + 1);
4631399Sahl 	dt_header_fmt_macro(mname, prp->pr_name);
4641399Sahl 
4651399Sahl 	fname = alloca(strlen(prp->pr_name) + 1 + i);
4661399Sahl 	dt_header_fmt_func(fname, prp->pr_name);
4671399Sahl 
4681399Sahl 	if (fprintf(infop->dthi_out, "#define\t%s_%s(",
4691399Sahl 	    infop->dthi_pmname, mname) < 0)
4701399Sahl 		return (dt_set_errno(dtp, errno));
4711399Sahl 
4721399Sahl 	for (i = 0; i < prp->pr_nargc; i++) {
4731399Sahl 		if (fprintf(infop->dthi_out, "arg%d", i) < 0)
4741399Sahl 			return (dt_set_errno(dtp, errno));
4751399Sahl 
4761399Sahl 		if (i + 1 != prp->pr_nargc &&
4771399Sahl 		    fprintf(infop->dthi_out, ", ") < 0)
4781399Sahl 			return (dt_set_errno(dtp, errno));
4791399Sahl 	}
4801399Sahl 
4812769Sahl 	if (!infop->dthi_empty) {
4822769Sahl 		if (fprintf(infop->dthi_out, ") \\\n\t") < 0)
4832769Sahl 			return (dt_set_errno(dtp, errno));
4841399Sahl 
4852769Sahl 		if (fprintf(infop->dthi_out, "__dtrace_%s___%s(",
4862769Sahl 		    infop->dthi_pfname, fname) < 0)
4871399Sahl 			return (dt_set_errno(dtp, errno));
4881399Sahl 
4892769Sahl 		for (i = 0; i < prp->pr_nargc; i++) {
4902769Sahl 			if (fprintf(infop->dthi_out, "arg%d", i) < 0)
4912769Sahl 				return (dt_set_errno(dtp, errno));
4922769Sahl 
4932769Sahl 			if (i + 1 != prp->pr_nargc &&
4942769Sahl 			    fprintf(infop->dthi_out, ", ") < 0)
4952769Sahl 				return (dt_set_errno(dtp, errno));
4962769Sahl 		}
4971399Sahl 	}
4981399Sahl 
4991399Sahl 	if (fprintf(infop->dthi_out, ")\n") < 0)
5001399Sahl 		return (dt_set_errno(dtp, errno));
5011399Sahl 
5022769Sahl 	if (!infop->dthi_empty) {
5036554Sahl 		if (fprintf(infop->dthi_out,
5046554Sahl 		    "#ifndef\t__sparc\n"
5056554Sahl 		    "#define\t%s_%s_ENABLED() \\\n"
5066554Sahl 		    "\t__dtraceenabled_%s___%s()\n"
5076554Sahl 		    "#else\n"
5086554Sahl 		    "#define\t%s_%s_ENABLED() \\\n"
5096554Sahl 		    "\t__dtraceenabled_%s___%s(0)\n"
5106554Sahl 		    "#endif\n",
5116554Sahl 		    infop->dthi_pmname, mname,
5126554Sahl 		    infop->dthi_pfname, fname,
5136554Sahl 		    infop->dthi_pmname, mname,
5146554Sahl 		    infop->dthi_pfname, fname) < 0)
5152769Sahl 			return (dt_set_errno(dtp, errno));
5161710Sahl 
5172769Sahl 	} else {
5182769Sahl 		if (fprintf(infop->dthi_out, "#define\t%s_%s_ENABLED() (0)\n",
5192769Sahl 		    infop->dthi_pmname, mname) < 0)
5202769Sahl 			return (dt_set_errno(dtp, errno));
5212769Sahl 	}
5221710Sahl 
5231399Sahl 	return (0);
5241399Sahl }
5251399Sahl 
5261399Sahl static int
5271399Sahl dt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out)
5281399Sahl {
5291399Sahl 	dt_header_info_t info;
5301399Sahl 	const char *p;
5311399Sahl 	int i;
5321399Sahl 
5331399Sahl 	if (pvp->pv_flags & DT_PROVIDER_IMPL)
5341399Sahl 		return (0);
5351399Sahl 
5362769Sahl 	/*
5372769Sahl 	 * Count the instances of the '-' character since we'll need to double
5382769Sahl 	 * those up.
5392769Sahl 	 */
5401399Sahl 	p = pvp->pv_desc.dtvd_name;
5411399Sahl 	for (i = 0; (p = strchr(p, '-')) != NULL; i++)
5421399Sahl 		p++;
5431399Sahl 
5441399Sahl 	info.dthi_dtp = dtp;
5451399Sahl 	info.dthi_out = out;
5462769Sahl 	info.dthi_empty = 0;
5471399Sahl 
5481399Sahl 	info.dthi_pmname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1);
5491399Sahl 	dt_header_fmt_macro(info.dthi_pmname, pvp->pv_desc.dtvd_name);
5501399Sahl 
5511399Sahl 	info.dthi_pfname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1 + i);
5521399Sahl 	dt_header_fmt_func(info.dthi_pfname, pvp->pv_desc.dtvd_name);
5531399Sahl 
5542769Sahl 	if (fprintf(out, "#if _DTRACE_VERSION\n\n") < 0)
5552769Sahl 		return (dt_set_errno(dtp, errno));
5561399Sahl 
5571399Sahl 	if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
5581399Sahl 		return (-1); /* dt_errno is set for us */
5591399Sahl 	if (fprintf(out, "\n\n") < 0)
5601399Sahl 		return (dt_set_errno(dtp, errno));
5611399Sahl 	if (dt_idhash_iter(pvp->pv_probes, dt_header_decl, &info) != 0)
5621399Sahl 		return (-1); /* dt_errno is set for us */
5631399Sahl 
5642769Sahl 	if (fprintf(out, "\n#else\n\n") < 0)
5652769Sahl 		return (dt_set_errno(dtp, errno));
5662769Sahl 
5672769Sahl 	info.dthi_empty = 1;
5682769Sahl 
5692769Sahl 	if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
5702769Sahl 		return (-1); /* dt_errno is set for us */
5712769Sahl 
5722769Sahl 	if (fprintf(out, "\n#endif\n\n") < 0)
5732769Sahl 		return (dt_set_errno(dtp, errno));
5742769Sahl 
5751399Sahl 	return (0);
5761399Sahl }
5771399Sahl 
5781399Sahl int
5791399Sahl dtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname)
5801399Sahl {
5811399Sahl 	dt_provider_t *pvp;
5821399Sahl 	char *mfname, *p;
5831399Sahl 
5841399Sahl 	if (fname != NULL) {
5851399Sahl 		if ((p = strrchr(fname, '/')) != NULL)
5861399Sahl 			fname = p + 1;
5871399Sahl 
5881399Sahl 		mfname = alloca(strlen(fname) + 1);
5891399Sahl 		dt_header_fmt_macro(mfname, fname);
5901399Sahl 		if (fprintf(out, "#ifndef\t_%s\n#define\t_%s\n\n",
5911399Sahl 		    mfname, mfname) < 0)
5921399Sahl 			return (dt_set_errno(dtp, errno));
5931399Sahl 	}
5941399Sahl 
5952769Sahl 	if (fprintf(out, "#include <unistd.h>\n\n") < 0)
5962769Sahl 		return (-1);
5972769Sahl 
5981399Sahl 	if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0)
5991399Sahl 		return (-1);
6001399Sahl 
6011399Sahl 	for (pvp = dt_list_next(&dtp->dt_provlist);
6021399Sahl 	    pvp != NULL; pvp = dt_list_next(pvp)) {
6031399Sahl 		if (dt_header_provider(dtp, pvp, out) != 0)
6041399Sahl 			return (-1); /* dt_errno is set for us */
6051399Sahl 	}
6061399Sahl 
6071399Sahl 	if (fprintf(out, "\n#ifdef\t__cplusplus\n}\n#endif\n") < 0)
6081399Sahl 		return (dt_set_errno(dtp, errno));
6091399Sahl 
6101399Sahl 	if (fname != NULL && fprintf(out, "\n#endif\t/* _%s */\n", mfname) < 0)
6111399Sahl 		return (dt_set_errno(dtp, errno));
6121399Sahl 
6131399Sahl 	return (0);
6141399Sahl }
615