17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
5ac44896ahl * Common Development and Distribution License (the "License").
6ac44896ahl * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
21900524fahl
227c478bdstevel@tonic-gate/*
23c9a6ea2Bryan Cantrill * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24deef35fEric Schrock * Copyright (c) 2011 by Delphix. All rights reserved.
257c478bdstevel@tonic-gate */
267c478bdstevel@tonic-gate
277c478bdstevel@tonic-gate#include <unistd.h>
287c478bdstevel@tonic-gate#include <strings.h>
297c478bdstevel@tonic-gate#include <stdlib.h>
307c478bdstevel@tonic-gate#include <errno.h>
317c478bdstevel@tonic-gate#include <assert.h>
32900524fahl#include <ctype.h>
33900524fahl#include <alloca.h>
347c478bdstevel@tonic-gate
357c478bdstevel@tonic-gate#include <dt_impl.h>
361a7c1b7mws#include <dt_program.h>
377c478bdstevel@tonic-gate#include <dt_printf.h>
38900524fahl#include <dt_provider.h>
397c478bdstevel@tonic-gate
407c478bdstevel@tonic-gatedtrace_prog_t *
411a7c1b7mwsdt_program_create(dtrace_hdl_t *dtp)
427c478bdstevel@tonic-gate{
431a7c1b7mws	dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t));
447c478bdstevel@tonic-gate
45c9a6ea2Bryan Cantrill	if (pgp != NULL) {
467c478bdstevel@tonic-gate		dt_list_append(&dtp->dt_programs, pgp);
47c9a6ea2Bryan Cantrill	} else {
487c478bdstevel@tonic-gate		(void) dt_set_errno(dtp, EDT_NOMEM);
49c9a6ea2Bryan Cantrill		return (NULL);
50c9a6ea2Bryan Cantrill	}
517c478bdstevel@tonic-gate
52ac44896ahl	/*
53ac44896ahl	 * By default, programs start with DOF version 1 so that output files
54ac44896ahl	 * containing DOF are backward compatible. If a program requires new
55ac44896ahl	 * DOF features, the version is increased as needed.
56ac44896ahl	 */
57ac44896ahl	pgp->dp_dofversion = DOF_VERSION_1;
58ac44896ahl
597c478bdstevel@tonic-gate	return (pgp);
607c478bdstevel@tonic-gate}
617c478bdstevel@tonic-gate
627c478bdstevel@tonic-gatevoid
631a7c1b7mwsdt_program_destroy(dtrace_hdl_t *dtp, dtrace_prog_t *pgp)
647c478bdstevel@tonic-gate{
657c478bdstevel@tonic-gate	dt_stmt_t *stp, *next;
661a7c1b7mws	uint_t i;
677c478bdstevel@tonic-gate
687c478bdstevel@tonic-gate	for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
697c478bdstevel@tonic-gate		next = dt_list_next(stp);
701a7c1b7mws		dtrace_stmt_destroy(dtp, stp->ds_desc);
711a7c1b7mws		dt_free(dtp, stp);
727c478bdstevel@tonic-gate	}
737c478bdstevel@tonic-gate
741a7c1b7mws	for (i = 0; i < pgp->dp_xrefslen; i++)
751a7c1b7mws		dt_free(dtp, pgp->dp_xrefs[i]);
761a7c1b7mws
771a7c1b7mws	dt_free(dtp, pgp->dp_xrefs);
787c478bdstevel@tonic-gate	dt_list_delete(&dtp->dt_programs, pgp);
791a7c1b7mws	dt_free(dtp, pgp);
807c478bdstevel@tonic-gate}
817c478bdstevel@tonic-gate
827c478bdstevel@tonic-gate/*ARGSUSED*/
837c478bdstevel@tonic-gatevoid
847c478bdstevel@tonic-gatedtrace_program_info(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
857c478bdstevel@tonic-gate    dtrace_proginfo_t *pip)
867c478bdstevel@tonic-gate{
877c478bdstevel@tonic-gate	dt_stmt_t *stp;
887c478bdstevel@tonic-gate	dtrace_actdesc_t *ap;
897c478bdstevel@tonic-gate	dtrace_ecbdesc_t *last = NULL;
907c478bdstevel@tonic-gate
917c478bdstevel@tonic-gate	if (pip == NULL)
927c478bdstevel@tonic-gate		return;
937c478bdstevel@tonic-gate
947c478bdstevel@tonic-gate	bzero(pip, sizeof (dtrace_proginfo_t));
957c478bdstevel@tonic-gate
967c478bdstevel@tonic-gate	if (dt_list_next(&pgp->dp_stmts) != NULL) {
977c478bdstevel@tonic-gate		pip->dpi_descattr = _dtrace_maxattr;
987c478bdstevel@tonic-gate		pip->dpi_stmtattr = _dtrace_maxattr;
997c478bdstevel@tonic-gate	} else {
1007c478bdstevel@tonic-gate		pip->dpi_descattr = _dtrace_defattr;
1017c478bdstevel@tonic-gate		pip->dpi_stmtattr = _dtrace_defattr;
1027c478bdstevel@tonic-gate	}
1037c478bdstevel@tonic-gate
1047c478bdstevel@tonic-gate	for (stp = dt_list_next(&pgp->dp_stmts); stp; stp = dt_list_next(stp)) {
1057c478bdstevel@tonic-gate		dtrace_ecbdesc_t *edp = stp->ds_desc->dtsd_ecbdesc;
1067c478bdstevel@tonic-gate
1077c478bdstevel@tonic-gate		if (edp == last)
1087c478bdstevel@tonic-gate			continue;
1097c478bdstevel@tonic-gate		last = edp;
1107c478bdstevel@tonic-gate
1117c478bdstevel@tonic-gate		pip->dpi_descattr =
1127c478bdstevel@tonic-gate		    dt_attr_min(stp->ds_desc->dtsd_descattr, pip->dpi_descattr);
1137c478bdstevel@tonic-gate
1147c478bdstevel@tonic-gate		pip->dpi_stmtattr =
1157c478bdstevel@tonic-gate		    dt_attr_min(stp->ds_desc->dtsd_stmtattr, pip->dpi_stmtattr);
1167c478bdstevel@tonic-gate
1177c478bdstevel@tonic-gate		/*
1187c478bdstevel@tonic-gate		 * If there aren't any actions, account for the fact that
1197c478bdstevel@tonic-gate		 * recording the epid will generate a record.
1207c478bdstevel@tonic-gate		 */
1217c478bdstevel@tonic-gate		if (edp->dted_action == NULL)
1227c478bdstevel@tonic-gate			pip->dpi_recgens++;
1237c478bdstevel@tonic-gate
1247c478bdstevel@tonic-gate		for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
1257c478bdstevel@tonic-gate			if (ap->dtad_kind == DTRACEACT_SPECULATE) {
1267c478bdstevel@tonic-gate				pip->dpi_speculations++;
1277c478bdstevel@tonic-gate				continue;
1287c478bdstevel@tonic-gate			}
1297c478bdstevel@tonic-gate
1307c478bdstevel@tonic-gate			if (DTRACEACT_ISAGG(ap->dtad_kind)) {
1317c478bdstevel@tonic-gate				pip->dpi_recgens -= ap->dtad_arg;
1327c478bdstevel@tonic-gate				pip->dpi_aggregates++;
1337c478bdstevel@tonic-gate				continue;
1347c478bdstevel@tonic-gate			}
1357c478bdstevel@tonic-gate
1367c478bdstevel@tonic-gate			if (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind))
1377c478bdstevel@tonic-gate				continue;
1387c478bdstevel@tonic-gate
1397c478bdstevel@tonic-gate			if (ap->dtad_kind == DTRACEACT_DIFEXPR &&
1407c478bdstevel@tonic-gate			    ap->dtad_difo->dtdo_rtype.dtdt_kind ==
1417c478bdstevel@tonic-gate			    DIF_TYPE_CTF &&
1427c478bdstevel@tonic-gate			    ap->dtad_difo->dtdo_rtype.dtdt_size == 0)
1437c478bdstevel@tonic-gate				continue;
1447c478bdstevel@tonic-gate
1457c478bdstevel@tonic-gate			pip->dpi_recgens++;
1467c478bdstevel@tonic-gate		}
1477c478bdstevel@tonic-gate	}
1487c478bdstevel@tonic-gate}
1497c478bdstevel@tonic-gate
1507c478bdstevel@tonic-gateint
1517c478bdstevel@tonic-gatedtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
1527c478bdstevel@tonic-gate    dtrace_proginfo_t *pip)
1537c478bdstevel@tonic-gate{
1547c478bdstevel@tonic-gate	void *dof;
1557c478bdstevel@tonic-gate	int n, err;
1567c478bdstevel@tonic-gate
1577c478bdstevel@tonic-gate	dtrace_program_info(dtp, pgp, pip);
1587c478bdstevel@tonic-gate
1597c478bdstevel@tonic-gate	if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL)
1607c478bdstevel@tonic-gate		return (-1);
1617c478bdstevel@tonic-gate
1627c478bdstevel@tonic-gate	n = dt_ioctl(dtp, DTRACEIOC_ENABLE, dof);
1637c478bdstevel@tonic-gate	dtrace_dof_destroy(dtp, dof);
1647c478bdstevel@tonic-gate
1657c478bdstevel@tonic-gate	if (n == -1) {
1667c478bdstevel@tonic-gate		switch (errno) {
1677c478bdstevel@tonic-gate		case EINVAL:
1687c478bdstevel@tonic-gate			err = EDT_DIFINVAL;
1697c478bdstevel@tonic-gate			break;
1707c478bdstevel@tonic-gate		case EFAULT:
1717c478bdstevel@tonic-gate			err = EDT_DIFFAULT;
1727c478bdstevel@tonic-gate			break;
1737c478bdstevel@tonic-gate		case E2BIG:
1747c478bdstevel@tonic-gate			err = EDT_DIFSIZE;
1757c478bdstevel@tonic-gate			break;
176b9e93c1Jonathan Haslam		case EBUSY:
177b9e93c1Jonathan Haslam			err = EDT_ENABLING_ERR;
178b9e93c1Jonathan Haslam			break;
1797c478bdstevel@tonic-gate		default:
1807c478bdstevel@tonic-gate			err = errno;
1817c478bdstevel@tonic-gate		}
1827c478bdstevel@tonic-gate
1837c478bdstevel@tonic-gate		return (dt_set_errno(dtp, err));
1847c478bdstevel@tonic-gate	}
1857c478bdstevel@tonic-gate
1867c478bdstevel@tonic-gate	if (pip != NULL)
1877c478bdstevel@tonic-gate		pip->dpi_matches += n;
1887c478bdstevel@tonic-gate
1897c478bdstevel@tonic-gate	return (0);
1907c478bdstevel@tonic-gate}
1917c478bdstevel@tonic-gate
1921a7c1b7mwsstatic void
1931a7c1b7mwsdt_ecbdesc_hold(dtrace_ecbdesc_t *edp)
1947c478bdstevel@tonic-gate{
1957c478bdstevel@tonic-gate	edp->dted_refcnt++;
1967c478bdstevel@tonic-gate}
1977c478bdstevel@tonic-gate
1987c478bdstevel@tonic-gatevoid
1991a7c1b7mwsdt_ecbdesc_release(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
2007c478bdstevel@tonic-gate{
2017c478bdstevel@tonic-gate	if (--edp->dted_refcnt > 0)
2027c478bdstevel@tonic-gate		return;
2037c478bdstevel@tonic-gate
2041a7c1b7mws	dt_difo_free(dtp, edp->dted_pred.dtpdd_difo);
2057c478bdstevel@tonic-gate	assert(edp->dted_action == NULL);
2061a7c1b7mws	dt_free(dtp, edp);
2077c478bdstevel@tonic-gate}
2087c478bdstevel@tonic-gate
2097c478bdstevel@tonic-gatedtrace_ecbdesc_t *
2101a7c1b7mwsdt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)
2117c478bdstevel@tonic-gate{
2127c478bdstevel@tonic-gate	dtrace_ecbdesc_t *edp;
2137c478bdstevel@tonic-gate
2141a7c1b7mws	if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) {
2157c478bdstevel@tonic-gate		(void) dt_set_errno(dtp, EDT_NOMEM);
2167c478bdstevel@tonic-gate		return (NULL);
2177c478bdstevel@tonic-gate	}
2187c478bdstevel@tonic-gate
2197c478bdstevel@tonic-gate	edp->dted_probe = *pdp;
2201a7c1b7mws	dt_ecbdesc_hold(edp);
2217c478bdstevel@tonic-gate	return (edp);
2227c478bdstevel@tonic-gate}
2237c478bdstevel@tonic-gate
2247c478bdstevel@tonic-gatedtrace_stmtdesc_t *
2257c478bdstevel@tonic-gatedtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
2267c478bdstevel@tonic-gate{
2277c478bdstevel@tonic-gate	dtrace_stmtdesc_t *sdp;
2287c478bdstevel@tonic-gate
2291a7c1b7mws	if ((sdp = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL)
2307c478bdstevel@tonic-gate		return (NULL);
2317c478bdstevel@tonic-gate
2321a7c1b7mws	dt_ecbdesc_hold(edp);
2337c478bdstevel@tonic-gate	sdp->dtsd_ecbdesc = edp;
2347c478bdstevel@tonic-gate	sdp->dtsd_descattr = _dtrace_defattr;
2357c478bdstevel@tonic-gate	sdp->dtsd_stmtattr = _dtrace_defattr;
2367c478bdstevel@tonic-gate
2377c478bdstevel@tonic-gate	return (sdp);
2387c478bdstevel@tonic-gate}
2397c478bdstevel@tonic-gate
2407c478bdstevel@tonic-gatedtrace_actdesc_t *
2417c478bdstevel@tonic-gatedtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
2427c478bdstevel@tonic-gate{
2437c478bdstevel@tonic-gate	dtrace_actdesc_t *new;
2447c478bdstevel@tonic-gate	dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
2457c478bdstevel@tonic-gate
2461a7c1b7mws	if ((new = dt_alloc(dtp, sizeof (dtrace_actdesc_t))) == NULL)
2477c478bdstevel@tonic-gate		return (NULL);
2487c478bdstevel@tonic-gate
2497c478bdstevel@tonic-gate	if (sdp->dtsd_action_last != NULL) {
2507c478bdstevel@tonic-gate		assert(sdp->dtsd_action != NULL);
2517c478bdstevel@tonic-gate		assert(sdp->dtsd_action_last->dtad_next == NULL);
2527c478bdstevel@tonic-gate		sdp->dtsd_action_last->dtad_next = new;
2537c478bdstevel@tonic-gate	} else {
2547c478bdstevel@tonic-gate		dtrace_actdesc_t *ap = edp->dted_action;
2557c478bdstevel@tonic-gate
2567c478bdstevel@tonic-gate		assert(sdp->dtsd_action == NULL);
2577c478bdstevel@tonic-gate		sdp->dtsd_action = new;
2587c478bdstevel@tonic-gate
2597c478bdstevel@tonic-gate		while (ap != NULL && ap->dtad_next != NULL)
2607c478bdstevel@tonic-gate			ap = ap->dtad_next;
2617c478bdstevel@tonic-gate
2627c478bdstevel@tonic-gate		if (ap == NULL)
2637c478bdstevel@tonic-gate			edp->dted_action = new;
2647c478bdstevel@tonic-gate		else
2657c478bdstevel@tonic-gate			ap->dtad_next = new;
2667c478bdstevel@tonic-gate	}
2677c478bdstevel@tonic-gate
2687c478bdstevel@tonic-gate	sdp->dtsd_action_last = new;
2697c478bdstevel@tonic-gate	bzero(new, sizeof (dtrace_actdesc_t));
2707c478bdstevel@tonic-gate	new->dtad_uarg = (uintptr_t)sdp;
2717c478bdstevel@tonic-gate
2727c478bdstevel@tonic-gate	return (new);
2737c478bdstevel@tonic-gate}
2747c478bdstevel@tonic-gate
2757c478bdstevel@tonic-gateint
2767c478bdstevel@tonic-gatedtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp)
2777c478bdstevel@tonic-gate{
2781a7c1b7mws	dt_stmt_t *stp = dt_alloc(dtp, sizeof (dt_stmt_t));
2797c478bdstevel@tonic-gate
2807c478bdstevel@tonic-gate	if (stp == NULL)
2811a7c1b7mws		return (-1); /* errno is set for us */
2827c478bdstevel@tonic-gate
2837c478bdstevel@tonic-gate	dt_list_append(&pgp->dp_stmts, stp);
2847c478bdstevel@tonic-gate	stp->ds_desc = sdp;
2857c478bdstevel@tonic-gate
2867c478bdstevel@tonic-gate	return (0);
2877c478bdstevel@tonic-gate}
2887c478bdstevel@tonic-gate
2897c478bdstevel@tonic-gateint
2907c478bdstevel@tonic-gatedtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
2917c478bdstevel@tonic-gate    dtrace_stmt_f *func, void *data)
2927c478bdstevel@tonic-gate{
2937c478bdstevel@tonic-gate	dt_stmt_t *stp, *next;
2947c478bdstevel@tonic-gate	int status = 0;
2957c478bdstevel@tonic-gate
2967c478bdstevel@tonic-gate	for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
2977c478bdstevel@tonic-gate		next = dt_list_next(stp);
2987c478bdstevel@tonic-gate		if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0)
2997c478bdstevel@tonic-gate			break;
3007c478bdstevel@tonic-gate	}
3017c478bdstevel@tonic-gate
3027c478bdstevel@tonic-gate	return (status);
3037c478bdstevel@tonic-gate}
3047c478bdstevel@tonic-gate
3057c478bdstevel@tonic-gatevoid
3061a7c1b7mwsdtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
3077c478bdstevel@tonic-gate{
3087c478bdstevel@tonic-gate	dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
3097c478bdstevel@tonic-gate
3107c478bdstevel@tonic-gate	/*
3117c478bdstevel@tonic-gate	 * We need to remove any actions that we have on this ECB, and
3127c478bdstevel@tonic-gate	 * remove our hold on the ECB itself.
3137c478bdstevel@tonic-gate	 */
3147c478bdstevel@tonic-gate	if (sdp->dtsd_action != NULL) {
3157c478bdstevel@tonic-gate		dtrace_actdesc_t *last = sdp->dtsd_action_last;
3167c478bdstevel@tonic-gate		dtrace_actdesc_t *ap, *next;
3177c478bdstevel@tonic-gate
3187c478bdstevel@tonic-gate		assert(last != NULL);
3197c478bdstevel@tonic-gate
3207c478bdstevel@tonic-gate		for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
3217c478bdstevel@tonic-gate			if (ap == sdp->dtsd_action)
3227c478bdstevel@tonic-gate				break;
3237c478bdstevel@tonic-gate
3247c478bdstevel@tonic-gate			if (ap->dtad_next == sdp->dtsd_action)
3257c478bdstevel@tonic-gate				break;
3267c478bdstevel@tonic-gate		}
3277c478bdstevel@tonic-gate
3287c478bdstevel@tonic-gate		assert(ap != NULL);
3297c478bdstevel@tonic-gate
3301a7c1b7mws		if (ap == edp->dted_action)
3317c478bdstevel@tonic-gate			edp->dted_action = last->dtad_next;
3321a7c1b7mws		else
3337c478bdstevel@tonic-gate			ap->dtad_next = last->dtad_next;
3347c478bdstevel@tonic-gate
3357c478bdstevel@tonic-gate		/*
3367c478bdstevel@tonic-gate		 * We have now removed our action list from its ECB; we can
3377c478bdstevel@tonic-gate		 * safely destroy the list.
3387c478bdstevel@tonic-gate		 */
3397c478bdstevel@tonic-gate		last->dtad_next = NULL;
3407c478bdstevel@tonic-gate
3417c478bdstevel@tonic-gate		for (ap = sdp->dtsd_action; ap != NULL; ap = next) {
3427c478bdstevel@tonic-gate			assert(ap->dtad_uarg == (uintptr_t)sdp);
3431a7c1b7mws			dt_difo_free(dtp, ap->dtad_difo);
3447c478bdstevel@tonic-gate			next = ap->dtad_next;
3451a7c1b7mws			dt_free(dtp, ap);
3467c478bdstevel@tonic-gate		}
3477c478bdstevel@tonic-gate	}
3487c478bdstevel@tonic-gate
3497c478bdstevel@tonic-gate	if (sdp->dtsd_fmtdata != NULL)
3507c478bdstevel@tonic-gate		dt_printf_destroy(sdp->dtsd_fmtdata);
351deef35fEric Schrock	dt_free(dtp, sdp->dtsd_strdata);
3527c478bdstevel@tonic-gate
3531a7c1b7mws	dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc);
3541a7c1b7mws	dt_free(dtp, sdp);
3557c478bdstevel@tonic-gate}
356900524fahl
357900524fahltypedef struct dt_header_info {
358900524fahl	dtrace_hdl_t *dthi_dtp;	/* consumer handle */
359900524fahl	FILE *dthi_out;		/* output file */
360900524fahl	char *dthi_pmname;	/* provider macro name */
361900524fahl	char *dthi_pfname;	/* provider function name */
3622b6e762ahl	int dthi_empty;		/* should we generate empty macros */
363900524fahl} dt_header_info_t;
364900524fahl
365900524fahlstatic void
366900524fahldt_header_fmt_macro(char *buf, const char *str)
367900524fahl{
368900524fahl	for (;;) {
369900524fahl		if (islower(*str)) {
370900524fahl			*buf++ = *str++ + 'A' - 'a';
371900524fahl		} else if (*str == '-') {
372900524fahl			*buf++ = '_';
373900524fahl			str++;
374900524fahl		} else if (*str == '.') {
375900524fahl			*buf++ = '_';
376900524fahl			str++;
377900524fahl		} else if ((*buf++ = *str++) == '\0') {
378900524fahl			break;
379900524fahl		}
380900524fahl	}
381900524fahl}
382900524fahl
383900524fahlstatic void
384900524fahldt_header_fmt_func(char *buf, const char *str)
385900524fahl{
386900524fahl	for (;;) {
387900524fahl		if (*str == '-') {
388900524fahl			*buf++ = '_';
389900524fahl			*buf++ = '_';
390900524fahl			str++;
391900524fahl		} else if ((*buf++ = *str++) == '\0') {
392900524fahl			break;
393900524fahl		}
394900524fahl	}
395900524fahl}
396900524fahl
397900524fahl/*ARGSUSED*/
398900524fahlstatic int
399900524fahldt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
400900524fahl{
401900524fahl	dt_header_info_t *infop = data;
402900524fahl	dtrace_hdl_t *dtp = infop->dthi_dtp;
403900524fahl	dt_probe_t *prp = idp->di_data;
404900524fahl	dt_node_t *dnp;
405900524fahl	char buf[DT_TYPE_NAMELEN];
406900524fahl	char *fname;
407900524fahl	const char *p;
408900524fahl	int i;
409900524fahl
410900524fahl	p = prp->pr_name;
411900524fahl	for (i = 0; (p = strchr(p, '-')) != NULL; i++)
412900524fahl		p++;
413900524fahl
414900524fahl	fname = alloca(strlen(prp->pr_name) + 1 + i);
415900524fahl	dt_header_fmt_func(fname, prp->pr_name);
416900524fahl
417900524fahl	if (fprintf(infop->dthi_out, "extern void __dtrace_%s___%s(",
418900524fahl	    infop->dthi_pfname, fname) < 0)
419900524fahl		return (dt_set_errno(dtp, errno));
420900524fahl
421900524fahl	for (dnp = prp->pr_nargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) {
422900524fahl		if (fprintf(infop->dthi_out, "%s",
423900524fahl		    ctf_type_name(dnp->dn_ctfp, dnp->dn_type,
424900524fahl		    buf, sizeof (buf))) < 0)
425900524fahl			return (dt_set_errno(dtp, errno));
426900524fahl
427900524fahl		if (i + 1 != prp->pr_nargc &&
428900524fahl		    fprintf(infop->dthi_out, ", ") < 0)
429900524fahl			return (dt_set_errno(dtp, errno));
430900524fahl	}
431900524fahl
432900524fahl	if (i == 0 && fprintf(infop->dthi_out, "void") < 0)
433900524fahl		return (dt_set_errno(dtp, errno));
434900524fahl
435900524fahl	if (fprintf(infop->dthi_out, ");\n") < 0)
436900524fahl		return (dt_set_errno(dtp, errno));
437900524fahl
4380bac14eahl	if (fprintf(infop->dthi_out,
4390bac14eahl	    "#ifndef\t__sparc\n"
4400bac14eahl	    "extern int __dtraceenabled_%s___%s(void);\n"
4410bac14eahl	    "#else\n"
4420bac14eahl	    "extern int __dtraceenabled_%s___%s(long);\n"
4430bac14eahl	    "#endif\n",
4440bac14eahl	    infop->dthi_pfname, fname, infop->dthi_pfname, fname) < 0)
445ac44896ahl		return (dt_set_errno(dtp, errno));
446ac44896ahl
447900524fahl	return (0);
448900524fahl}
449900524fahl
450900524fahl/*ARGSUSED*/
451900524fahlstatic int
452900524fahldt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
453900524fahl{
454900524fahl	dt_header_info_t *infop = data;
455900524fahl	dtrace_hdl_t *dtp = infop->dthi_dtp;
456900524fahl	dt_probe_t *prp = idp->di_data;
457900524fahl	char *mname, *fname;
458900524fahl	const char *p;
459900524fahl	int i;
460900524fahl
461900524fahl	p = prp->pr_name;
462900524fahl	for (i = 0; (p = strchr(p, '-')) != NULL; i++)
463900524fahl		p++;
464900524fahl
465900524fahl	mname = alloca(strlen(prp->pr_name) + 1);
466900524fahl	dt_header_fmt_macro(mname, prp->pr_name);
467900524fahl
468900524fahl	fname = alloca(strlen(prp->pr_name) + 1 + i);
469900524fahl	dt_header_fmt_func(fname, prp->pr_name);
470900524fahl
471900524fahl	if (fprintf(infop->dthi_out, "#define\t%s_%s(",
472900524fahl	    infop->dthi_pmname, mname) < 0)
473900524fahl		return (dt_set_errno(dtp, errno));
474900524fahl
475900524fahl	for (i = 0; i < prp->pr_nargc; i++) {
476900524fahl		if (fprintf(infop->dthi_out, "arg%d", i) < 0)
477900524fahl			return (dt_set_errno(dtp, errno));
478900524fahl
479900524fahl		if (i + 1 != prp->pr_nargc &&
480900524fahl		    fprintf(infop->dthi_out, ", ") < 0)
481900524fahl			return (dt_set_errno(dtp, errno));
482900524fahl	}
483900524fahl
4842b6e762ahl	if (!infop->dthi_empty) {
4852b6e762ahl		if (fprintf(infop->dthi_out, ") \\\n\t") < 0)
486900524fahl			return (dt_set_errno(dtp, errno));
487900524fahl
4882b6e762ahl		if (fprintf(infop->dthi_out, "__dtrace_%s___%s(",
4892b6e762ahl		    infop->dthi_pfname, fname) < 0)
490900524fahl			return (dt_set_errno(dtp, errno));
4912b6e762ahl
4922b6e762ahl		for (i = 0; i < prp->pr_nargc; i++) {
4932b6e762ahl			if (fprintf(infop->dthi_out, "arg%d", i) < 0)
4942b6e762ahl				return (dt_set_errno(dtp, errno));
4952b6e762ahl
4962b6e762ahl			if (i + 1 != prp->pr_nargc &&
4972b6e762ahl			    fprintf(infop->dthi_out, ", ") < 0)
4982b6e762ahl				return (dt_set_errno(dtp, errno));
4992b6e762ahl		}
500900524fahl	}
501900524fahl
502900524fahl	if (fprintf(infop->dthi_out, ")\n") < 0)
503900524fahl		return (dt_set_errno(dtp, errno));
504900524fahl
5052b6e762ahl	if (!infop->dthi_empty) {
5060bac14eahl		if (fprintf(infop->dthi_out,
5070bac14eahl		    "#ifndef\t__sparc\n"
5080bac14eahl		    "#define\t%s_%s_ENABLED() \\\n"
5090bac14eahl		    "\t__dtraceenabled_%s___%s()\n"
5100bac14eahl		    "#else\n"
5110bac14eahl		    "#define\t%s_%s_ENABLED() \\\n"
5120bac14eahl		    "\t__dtraceenabled_%s___%s(0)\n"
5130bac14eahl		    "#endif\n",
5140bac14eahl		    infop->dthi_pmname, mname,
5150bac14eahl		    infop->dthi_pfname, fname,
5160bac14eahl		    infop->dthi_pmname, mname,
5172b6e762ahl		    infop->dthi_pfname, fname) < 0)
5182b6e762ahl			return (dt_set_errno(dtp, errno));
5190bac14eahl
5202b6e762ahl	} else {
5212b6e762ahl		if (fprintf(infop->dthi_out, "#define\t%s_%s_ENABLED() (0)\n",
5222b6e762ahl		    infop->dthi_pmname, mname) < 0)
5232b6e762ahl			return (dt_set_errno(dtp, errno));
5242b6e762ahl	}
525ac44896ahl
526900524fahl	return (0);
527900524fahl}
528900524fahl
529900524fahlstatic int
530900524fahldt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out)
531900524fahl{
532900524fahl	dt_header_info_t info;
533900524fahl	const char *p;
534900524fahl	int i;
535900524fahl
536900524fahl	if (pvp->pv_flags & DT_PROVIDER_IMPL)
537900524fahl		return (0);
538900524fahl
5392b6e762ahl	/*
5402b6e762ahl	 * Count the instances of the '-' character since we'll need to double
5412b6e762ahl	 * those up.
5422b6e762ahl	 */
543900524fahl	p = pvp->pv_desc.dtvd_name;
544900524fahl	for (i = 0; (p = strchr(p, '-')) != NULL; i++)
545900524fahl		p++;
546900524fahl
547900524fahl	info.dthi_dtp = dtp;
548900524fahl	info.dthi_out = out;
5492b6e762ahl	info.dthi_empty = 0;
550900524fahl
551900524fahl	info.dthi_pmname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1);
552900524fahl	dt_header_fmt_macro(info.dthi_pmname, pvp->pv_desc.dtvd_name);
553900524fahl
554900524fahl	info.dthi_pfname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1 + i);
555900524fahl	dt_header_fmt_func(info.dthi_pfname, pvp->pv_desc.dtvd_name);
556900524fahl
5572b6e762ahl	if (fprintf(out, "#if _DTRACE_VERSION\n\n") < 0)
5582b6e762ahl		return (dt_set_errno(dtp, errno));
559900524fahl
560900524fahl	if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
561900524fahl		return (-1); /* dt_errno is set for us */
562900524fahl	if (fprintf(out, "\n\n") < 0)
563900524fahl		return (dt_set_errno(dtp, errno));
564900524fahl	if (dt_idhash_iter(pvp->pv_probes, dt_header_decl, &info) != 0)
565900524fahl		return (-1); /* dt_errno is set for us */
566900524fahl
5672b6e762ahl	if (fprintf(out, "\n#else\n\n") < 0)
5682b6e762ahl		return (dt_set_errno(dtp, errno));
5692b6e762ahl
5702b6e762ahl	info.dthi_empty = 1;
5712b6e762ahl
5722b6e762ahl	if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
5732b6e762ahl		return (-1); /* dt_errno is set for us */
5742b6e762ahl
5752b6e762ahl	if (fprintf(out, "\n#endif\n\n") < 0)
5762b6e762ahl		return (dt_set_errno(dtp, errno));
5772b6e762ahl
578900524fahl	return (0);
579900524fahl}
580900524fahl
581900524fahlint
582900524fahldtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname)
583900524fahl{
584900524fahl	dt_provider_t *pvp;
585900524fahl	char *mfname, *p;
586900524fahl
587900524fahl	if (fname != NULL) {
588900524fahl		if ((p = strrchr(fname, '/')) != NULL)
589900524fahl			fname = p + 1;
590900524fahl
591900524fahl		mfname = alloca(strlen(fname) + 1);
592900524fahl		dt_header_fmt_macro(mfname, fname);
593900524fahl		if (fprintf(out, "#ifndef\t_%s\n#define\t_%s\n\n",
594900524fahl		    mfname, mfname) < 0)
595900524fahl			return (dt_set_errno(dtp, errno));
596900524fahl	}
597900524fahl
5982b6e762ahl	if (fprintf(out, "#include <unistd.h>\n\n") < 0)
5992b6e762ahl		return (-1);
6002b6e762ahl
601900524fahl	if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0)
602900524fahl		return (-1);
603900524fahl
604900524fahl	for (pvp = dt_list_next(&dtp->dt_provlist);
605900524fahl	    pvp != NULL; pvp = dt_list_next(pvp)) {
606900524fahl		if (dt_header_provider(dtp, pvp, out) != 0)
607900524fahl			return (-1); /* dt_errno is set for us */
608900524fahl	}
609900524fahl
610900524fahl	if (fprintf(out, "\n#ifdef\t__cplusplus\n}\n#endif\n") < 0)
611900524fahl		return (dt_set_errno(dtp, errno));
612900524fahl
613900524fahl	if (fname != NULL && fprintf(out, "\n#endif\t/* _%s */\n", mfname) < 0)
614900524fahl		return (dt_set_errno(dtp, errno));
615900524fahl
616900524fahl	return (0);
617900524fahl}
618