1178479Sjb/*
2178479Sjb * CDDL HEADER START
3178479Sjb *
4178479Sjb * The contents of this file are subject to the terms of the
5178479Sjb * Common Development and Distribution License (the "License").
6178479Sjb * You may not use this file except in compliance with the License.
7178479Sjb *
8178479Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9178479Sjb * or http://www.opensolaris.org/os/licensing.
10178479Sjb * See the License for the specific language governing permissions
11178479Sjb * and limitations under the License.
12178479Sjb *
13178479Sjb * When distributing Covered Code, include this CDDL HEADER in each
14178479Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15178479Sjb * If applicable, add the following below this CDDL HEADER, with the
16178479Sjb * fields enclosed by brackets "[]" replaced with your own identifying
17178479Sjb * information: Portions Copyright [yyyy] [name of copyright owner]
18178479Sjb *
19178479Sjb * CDDL HEADER END
20178479Sjb */
21178479Sjb
22178479Sjb/*
23210767Srpaulo * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24248708Spfg * Copyright (c) 2011 by Delphix. All rights reserved.
25178479Sjb */
26178479Sjb
27178479Sjb#include <unistd.h>
28178479Sjb#include <strings.h>
29178479Sjb#include <stdlib.h>
30178479Sjb#include <errno.h>
31178479Sjb#include <assert.h>
32178479Sjb#include <ctype.h>
33178553Sjb#if defined(sun)
34178479Sjb#include <alloca.h>
35178553Sjb#endif
36178479Sjb
37178479Sjb#include <dt_impl.h>
38178479Sjb#include <dt_program.h>
39178479Sjb#include <dt_printf.h>
40178479Sjb#include <dt_provider.h>
41178479Sjb
42178479Sjbdtrace_prog_t *
43178479Sjbdt_program_create(dtrace_hdl_t *dtp)
44178479Sjb{
45178479Sjb	dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t));
46178479Sjb
47210767Srpaulo	if (pgp != NULL) {
48178479Sjb		dt_list_append(&dtp->dt_programs, pgp);
49210767Srpaulo	} else {
50178479Sjb		(void) dt_set_errno(dtp, EDT_NOMEM);
51210767Srpaulo		return (NULL);
52210767Srpaulo	}
53178479Sjb
54178479Sjb	/*
55178479Sjb	 * By default, programs start with DOF version 1 so that output files
56178479Sjb	 * containing DOF are backward compatible. If a program requires new
57178479Sjb	 * DOF features, the version is increased as needed.
58178479Sjb	 */
59178479Sjb	pgp->dp_dofversion = DOF_VERSION_1;
60178479Sjb
61178479Sjb	return (pgp);
62178479Sjb}
63178479Sjb
64178479Sjbvoid
65178479Sjbdt_program_destroy(dtrace_hdl_t *dtp, dtrace_prog_t *pgp)
66178479Sjb{
67178479Sjb	dt_stmt_t *stp, *next;
68178479Sjb	uint_t i;
69178479Sjb
70178479Sjb	for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
71178479Sjb		next = dt_list_next(stp);
72178479Sjb		dtrace_stmt_destroy(dtp, stp->ds_desc);
73178479Sjb		dt_free(dtp, stp);
74178479Sjb	}
75178479Sjb
76178479Sjb	for (i = 0; i < pgp->dp_xrefslen; i++)
77178479Sjb		dt_free(dtp, pgp->dp_xrefs[i]);
78178479Sjb
79178479Sjb	dt_free(dtp, pgp->dp_xrefs);
80178479Sjb	dt_list_delete(&dtp->dt_programs, pgp);
81178479Sjb	dt_free(dtp, pgp);
82178479Sjb}
83178479Sjb
84178479Sjb/*ARGSUSED*/
85178479Sjbvoid
86178479Sjbdtrace_program_info(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
87178479Sjb    dtrace_proginfo_t *pip)
88178479Sjb{
89178479Sjb	dt_stmt_t *stp;
90178479Sjb	dtrace_actdesc_t *ap;
91178479Sjb	dtrace_ecbdesc_t *last = NULL;
92178479Sjb
93178479Sjb	if (pip == NULL)
94178479Sjb		return;
95178479Sjb
96178479Sjb	bzero(pip, sizeof (dtrace_proginfo_t));
97178479Sjb
98178479Sjb	if (dt_list_next(&pgp->dp_stmts) != NULL) {
99178479Sjb		pip->dpi_descattr = _dtrace_maxattr;
100178479Sjb		pip->dpi_stmtattr = _dtrace_maxattr;
101178479Sjb	} else {
102178479Sjb		pip->dpi_descattr = _dtrace_defattr;
103178479Sjb		pip->dpi_stmtattr = _dtrace_defattr;
104178479Sjb	}
105178479Sjb
106178479Sjb	for (stp = dt_list_next(&pgp->dp_stmts); stp; stp = dt_list_next(stp)) {
107178479Sjb		dtrace_ecbdesc_t *edp = stp->ds_desc->dtsd_ecbdesc;
108178479Sjb
109178479Sjb		if (edp == last)
110178479Sjb			continue;
111178479Sjb		last = edp;
112178479Sjb
113178479Sjb		pip->dpi_descattr =
114178479Sjb		    dt_attr_min(stp->ds_desc->dtsd_descattr, pip->dpi_descattr);
115178479Sjb
116178479Sjb		pip->dpi_stmtattr =
117178479Sjb		    dt_attr_min(stp->ds_desc->dtsd_stmtattr, pip->dpi_stmtattr);
118178479Sjb
119178479Sjb		/*
120178479Sjb		 * If there aren't any actions, account for the fact that
121178479Sjb		 * recording the epid will generate a record.
122178479Sjb		 */
123178479Sjb		if (edp->dted_action == NULL)
124178479Sjb			pip->dpi_recgens++;
125178479Sjb
126178479Sjb		for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
127178479Sjb			if (ap->dtad_kind == DTRACEACT_SPECULATE) {
128178479Sjb				pip->dpi_speculations++;
129178479Sjb				continue;
130178479Sjb			}
131178479Sjb
132178479Sjb			if (DTRACEACT_ISAGG(ap->dtad_kind)) {
133178479Sjb				pip->dpi_recgens -= ap->dtad_arg;
134178479Sjb				pip->dpi_aggregates++;
135178479Sjb				continue;
136178479Sjb			}
137178479Sjb
138178479Sjb			if (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind))
139178479Sjb				continue;
140178479Sjb
141178479Sjb			if (ap->dtad_kind == DTRACEACT_DIFEXPR &&
142178479Sjb			    ap->dtad_difo->dtdo_rtype.dtdt_kind ==
143178479Sjb			    DIF_TYPE_CTF &&
144178479Sjb			    ap->dtad_difo->dtdo_rtype.dtdt_size == 0)
145178479Sjb				continue;
146178479Sjb
147178479Sjb			pip->dpi_recgens++;
148178479Sjb		}
149178479Sjb	}
150178479Sjb}
151178479Sjb
152178479Sjbint
153178479Sjbdtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
154178479Sjb    dtrace_proginfo_t *pip)
155178479Sjb{
156178553Sjb	dtrace_enable_io_t args;
157178479Sjb	void *dof;
158178479Sjb	int n, err;
159178479Sjb
160178479Sjb	dtrace_program_info(dtp, pgp, pip);
161178479Sjb
162178479Sjb	if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL)
163178479Sjb		return (-1);
164178479Sjb
165178553Sjb	args.dof = dof;
166178553Sjb	args.n_matched = 0;
167178553Sjb	n = dt_ioctl(dtp, DTRACEIOC_ENABLE, &args);
168178479Sjb	dtrace_dof_destroy(dtp, dof);
169178479Sjb
170178479Sjb	if (n == -1) {
171178479Sjb		switch (errno) {
172178479Sjb		case EINVAL:
173178479Sjb			err = EDT_DIFINVAL;
174178479Sjb			break;
175178479Sjb		case EFAULT:
176178479Sjb			err = EDT_DIFFAULT;
177178479Sjb			break;
178178479Sjb		case E2BIG:
179178479Sjb			err = EDT_DIFSIZE;
180178479Sjb			break;
181210767Srpaulo		case EBUSY:
182210767Srpaulo			err = EDT_ENABLING_ERR;
183210767Srpaulo			break;
184178479Sjb		default:
185178479Sjb			err = errno;
186178479Sjb		}
187178479Sjb
188178479Sjb		return (dt_set_errno(dtp, err));
189178479Sjb	}
190178479Sjb
191178479Sjb	if (pip != NULL)
192178553Sjb		pip->dpi_matches += args.n_matched;
193178479Sjb
194178479Sjb	return (0);
195178479Sjb}
196178479Sjb
197178479Sjbstatic void
198178479Sjbdt_ecbdesc_hold(dtrace_ecbdesc_t *edp)
199178479Sjb{
200178479Sjb	edp->dted_refcnt++;
201178479Sjb}
202178479Sjb
203178479Sjbvoid
204178479Sjbdt_ecbdesc_release(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
205178479Sjb{
206178479Sjb	if (--edp->dted_refcnt > 0)
207178479Sjb		return;
208178479Sjb
209178479Sjb	dt_difo_free(dtp, edp->dted_pred.dtpdd_difo);
210178479Sjb	assert(edp->dted_action == NULL);
211178479Sjb	dt_free(dtp, edp);
212178479Sjb}
213178479Sjb
214178479Sjbdtrace_ecbdesc_t *
215178479Sjbdt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)
216178479Sjb{
217178479Sjb	dtrace_ecbdesc_t *edp;
218178479Sjb
219178479Sjb	if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) {
220178479Sjb		(void) dt_set_errno(dtp, EDT_NOMEM);
221178479Sjb		return (NULL);
222178479Sjb	}
223178479Sjb
224178479Sjb	edp->dted_probe = *pdp;
225178479Sjb	dt_ecbdesc_hold(edp);
226178479Sjb	return (edp);
227178479Sjb}
228178479Sjb
229178479Sjbdtrace_stmtdesc_t *
230178479Sjbdtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
231178479Sjb{
232178479Sjb	dtrace_stmtdesc_t *sdp;
233178479Sjb
234178479Sjb	if ((sdp = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL)
235178479Sjb		return (NULL);
236178479Sjb
237178479Sjb	dt_ecbdesc_hold(edp);
238178479Sjb	sdp->dtsd_ecbdesc = edp;
239178479Sjb	sdp->dtsd_descattr = _dtrace_defattr;
240178479Sjb	sdp->dtsd_stmtattr = _dtrace_defattr;
241178479Sjb
242178479Sjb	return (sdp);
243178479Sjb}
244178479Sjb
245178479Sjbdtrace_actdesc_t *
246178479Sjbdtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
247178479Sjb{
248178479Sjb	dtrace_actdesc_t *new;
249178479Sjb	dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
250178479Sjb
251178479Sjb	if ((new = dt_alloc(dtp, sizeof (dtrace_actdesc_t))) == NULL)
252178479Sjb		return (NULL);
253178479Sjb
254178479Sjb	if (sdp->dtsd_action_last != NULL) {
255178479Sjb		assert(sdp->dtsd_action != NULL);
256178479Sjb		assert(sdp->dtsd_action_last->dtad_next == NULL);
257178479Sjb		sdp->dtsd_action_last->dtad_next = new;
258178479Sjb	} else {
259178479Sjb		dtrace_actdesc_t *ap = edp->dted_action;
260178479Sjb
261178479Sjb		assert(sdp->dtsd_action == NULL);
262178479Sjb		sdp->dtsd_action = new;
263178479Sjb
264178479Sjb		while (ap != NULL && ap->dtad_next != NULL)
265178479Sjb			ap = ap->dtad_next;
266178479Sjb
267178479Sjb		if (ap == NULL)
268178479Sjb			edp->dted_action = new;
269178479Sjb		else
270178479Sjb			ap->dtad_next = new;
271178479Sjb	}
272178479Sjb
273178479Sjb	sdp->dtsd_action_last = new;
274178479Sjb	bzero(new, sizeof (dtrace_actdesc_t));
275178479Sjb	new->dtad_uarg = (uintptr_t)sdp;
276178479Sjb
277178479Sjb	return (new);
278178479Sjb}
279178479Sjb
280178479Sjbint
281178479Sjbdtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp)
282178479Sjb{
283178479Sjb	dt_stmt_t *stp = dt_alloc(dtp, sizeof (dt_stmt_t));
284178479Sjb
285178479Sjb	if (stp == NULL)
286178479Sjb		return (-1); /* errno is set for us */
287178479Sjb
288178479Sjb	dt_list_append(&pgp->dp_stmts, stp);
289178479Sjb	stp->ds_desc = sdp;
290178479Sjb
291178479Sjb	return (0);
292178479Sjb}
293178479Sjb
294178479Sjbint
295178479Sjbdtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
296178479Sjb    dtrace_stmt_f *func, void *data)
297178479Sjb{
298178479Sjb	dt_stmt_t *stp, *next;
299178479Sjb	int status = 0;
300178479Sjb
301178479Sjb	for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
302178479Sjb		next = dt_list_next(stp);
303178479Sjb		if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0)
304178479Sjb			break;
305178479Sjb	}
306178479Sjb
307178479Sjb	return (status);
308178479Sjb}
309178479Sjb
310178479Sjbvoid
311178479Sjbdtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
312178479Sjb{
313178479Sjb	dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
314178479Sjb
315178479Sjb	/*
316178479Sjb	 * We need to remove any actions that we have on this ECB, and
317178479Sjb	 * remove our hold on the ECB itself.
318178479Sjb	 */
319178479Sjb	if (sdp->dtsd_action != NULL) {
320178479Sjb		dtrace_actdesc_t *last = sdp->dtsd_action_last;
321178479Sjb		dtrace_actdesc_t *ap, *next;
322178479Sjb
323178479Sjb		assert(last != NULL);
324178479Sjb
325178479Sjb		for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
326178479Sjb			if (ap == sdp->dtsd_action)
327178479Sjb				break;
328178479Sjb
329178479Sjb			if (ap->dtad_next == sdp->dtsd_action)
330178479Sjb				break;
331178479Sjb		}
332178479Sjb
333178479Sjb		assert(ap != NULL);
334178479Sjb
335178479Sjb		if (ap == edp->dted_action)
336178479Sjb			edp->dted_action = last->dtad_next;
337178479Sjb		else
338178479Sjb			ap->dtad_next = last->dtad_next;
339178479Sjb
340178479Sjb		/*
341178479Sjb		 * We have now removed our action list from its ECB; we can
342178479Sjb		 * safely destroy the list.
343178479Sjb		 */
344178479Sjb		last->dtad_next = NULL;
345178479Sjb
346178479Sjb		for (ap = sdp->dtsd_action; ap != NULL; ap = next) {
347178479Sjb			assert(ap->dtad_uarg == (uintptr_t)sdp);
348178479Sjb			dt_difo_free(dtp, ap->dtad_difo);
349178479Sjb			next = ap->dtad_next;
350178479Sjb			dt_free(dtp, ap);
351178479Sjb		}
352178479Sjb	}
353178479Sjb
354178479Sjb	if (sdp->dtsd_fmtdata != NULL)
355178479Sjb		dt_printf_destroy(sdp->dtsd_fmtdata);
356248708Spfg	dt_free(dtp, sdp->dtsd_strdata);
357178479Sjb
358178479Sjb	dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc);
359178479Sjb	dt_free(dtp, sdp);
360178479Sjb}
361178479Sjb
362178479Sjbtypedef struct dt_header_info {
363178479Sjb	dtrace_hdl_t *dthi_dtp;	/* consumer handle */
364178479Sjb	FILE *dthi_out;		/* output file */
365178479Sjb	char *dthi_pmname;	/* provider macro name */
366178479Sjb	char *dthi_pfname;	/* provider function name */
367178479Sjb	int dthi_empty;		/* should we generate empty macros */
368178479Sjb} dt_header_info_t;
369178479Sjb
370178479Sjbstatic void
371178479Sjbdt_header_fmt_macro(char *buf, const char *str)
372178479Sjb{
373178479Sjb	for (;;) {
374178479Sjb		if (islower(*str)) {
375178479Sjb			*buf++ = *str++ + 'A' - 'a';
376178479Sjb		} else if (*str == '-') {
377178479Sjb			*buf++ = '_';
378178479Sjb			str++;
379178479Sjb		} else if (*str == '.') {
380178479Sjb			*buf++ = '_';
381178479Sjb			str++;
382178479Sjb		} else if ((*buf++ = *str++) == '\0') {
383178479Sjb			break;
384178479Sjb		}
385178479Sjb	}
386178479Sjb}
387178479Sjb
388178479Sjbstatic void
389178479Sjbdt_header_fmt_func(char *buf, const char *str)
390178479Sjb{
391178479Sjb	for (;;) {
392178479Sjb		if (*str == '-') {
393178479Sjb			*buf++ = '_';
394178479Sjb			*buf++ = '_';
395178479Sjb			str++;
396178479Sjb		} else if ((*buf++ = *str++) == '\0') {
397178479Sjb			break;
398178479Sjb		}
399178479Sjb	}
400178479Sjb}
401178479Sjb
402178479Sjb/*ARGSUSED*/
403178479Sjbstatic int
404178479Sjbdt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
405178479Sjb{
406178479Sjb	dt_header_info_t *infop = data;
407178479Sjb	dtrace_hdl_t *dtp = infop->dthi_dtp;
408178479Sjb	dt_probe_t *prp = idp->di_data;
409178479Sjb	dt_node_t *dnp;
410178479Sjb	char buf[DT_TYPE_NAMELEN];
411178479Sjb	char *fname;
412178479Sjb	const char *p;
413178479Sjb	int i;
414178479Sjb
415178479Sjb	p = prp->pr_name;
416178479Sjb	for (i = 0; (p = strchr(p, '-')) != NULL; i++)
417178479Sjb		p++;
418178479Sjb
419178479Sjb	fname = alloca(strlen(prp->pr_name) + 1 + i);
420178479Sjb	dt_header_fmt_func(fname, prp->pr_name);
421178479Sjb
422178479Sjb	if (fprintf(infop->dthi_out, "extern void __dtrace_%s___%s(",
423178479Sjb	    infop->dthi_pfname, fname) < 0)
424178479Sjb		return (dt_set_errno(dtp, errno));
425178479Sjb
426178479Sjb	for (dnp = prp->pr_nargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) {
427178479Sjb		if (fprintf(infop->dthi_out, "%s",
428178479Sjb		    ctf_type_name(dnp->dn_ctfp, dnp->dn_type,
429178479Sjb		    buf, sizeof (buf))) < 0)
430178479Sjb			return (dt_set_errno(dtp, errno));
431178479Sjb
432178479Sjb		if (i + 1 != prp->pr_nargc &&
433178479Sjb		    fprintf(infop->dthi_out, ", ") < 0)
434178479Sjb			return (dt_set_errno(dtp, errno));
435178479Sjb	}
436178479Sjb
437178479Sjb	if (i == 0 && fprintf(infop->dthi_out, "void") < 0)
438178479Sjb		return (dt_set_errno(dtp, errno));
439178479Sjb
440178479Sjb	if (fprintf(infop->dthi_out, ");\n") < 0)
441178479Sjb		return (dt_set_errno(dtp, errno));
442178479Sjb
443184696Srodrigc	if (fprintf(infop->dthi_out,
444184696Srodrigc	    "#ifndef\t__sparc\n"
445184696Srodrigc	    "extern int __dtraceenabled_%s___%s(void);\n"
446184696Srodrigc	    "#else\n"
447184696Srodrigc	    "extern int __dtraceenabled_%s___%s(long);\n"
448184696Srodrigc	    "#endif\n",
449184696Srodrigc	    infop->dthi_pfname, fname, infop->dthi_pfname, fname) < 0)
450178479Sjb		return (dt_set_errno(dtp, errno));
451178479Sjb
452178479Sjb	return (0);
453178479Sjb}
454178479Sjb
455178479Sjb/*ARGSUSED*/
456178479Sjbstatic int
457178479Sjbdt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
458178479Sjb{
459178479Sjb	dt_header_info_t *infop = data;
460178479Sjb	dtrace_hdl_t *dtp = infop->dthi_dtp;
461178479Sjb	dt_probe_t *prp = idp->di_data;
462178479Sjb	char *mname, *fname;
463178479Sjb	const char *p;
464178479Sjb	int i;
465178479Sjb
466178479Sjb	p = prp->pr_name;
467178479Sjb	for (i = 0; (p = strchr(p, '-')) != NULL; i++)
468178479Sjb		p++;
469178479Sjb
470178479Sjb	mname = alloca(strlen(prp->pr_name) + 1);
471178479Sjb	dt_header_fmt_macro(mname, prp->pr_name);
472178479Sjb
473178479Sjb	fname = alloca(strlen(prp->pr_name) + 1 + i);
474178479Sjb	dt_header_fmt_func(fname, prp->pr_name);
475178479Sjb
476178479Sjb	if (fprintf(infop->dthi_out, "#define\t%s_%s(",
477178479Sjb	    infop->dthi_pmname, mname) < 0)
478178479Sjb		return (dt_set_errno(dtp, errno));
479178479Sjb
480178479Sjb	for (i = 0; i < prp->pr_nargc; i++) {
481178479Sjb		if (fprintf(infop->dthi_out, "arg%d", i) < 0)
482178479Sjb			return (dt_set_errno(dtp, errno));
483178479Sjb
484178479Sjb		if (i + 1 != prp->pr_nargc &&
485178479Sjb		    fprintf(infop->dthi_out, ", ") < 0)
486178479Sjb			return (dt_set_errno(dtp, errno));
487178479Sjb	}
488178479Sjb
489178479Sjb	if (!infop->dthi_empty) {
490178479Sjb		if (fprintf(infop->dthi_out, ") \\\n\t") < 0)
491178479Sjb			return (dt_set_errno(dtp, errno));
492178479Sjb
493178479Sjb		if (fprintf(infop->dthi_out, "__dtrace_%s___%s(",
494178479Sjb		    infop->dthi_pfname, fname) < 0)
495178479Sjb			return (dt_set_errno(dtp, errno));
496178479Sjb
497178479Sjb		for (i = 0; i < prp->pr_nargc; i++) {
498178479Sjb			if (fprintf(infop->dthi_out, "arg%d", i) < 0)
499178479Sjb				return (dt_set_errno(dtp, errno));
500178479Sjb
501178479Sjb			if (i + 1 != prp->pr_nargc &&
502178479Sjb			    fprintf(infop->dthi_out, ", ") < 0)
503178479Sjb				return (dt_set_errno(dtp, errno));
504178479Sjb		}
505178479Sjb	}
506178479Sjb
507178479Sjb	if (fprintf(infop->dthi_out, ")\n") < 0)
508178479Sjb		return (dt_set_errno(dtp, errno));
509178479Sjb
510178479Sjb	if (!infop->dthi_empty) {
511184696Srodrigc		if (fprintf(infop->dthi_out,
512184696Srodrigc		    "#ifndef\t__sparc\n"
513184696Srodrigc		    "#define\t%s_%s_ENABLED() \\\n"
514184696Srodrigc		    "\t__dtraceenabled_%s___%s()\n"
515184696Srodrigc		    "#else\n"
516184696Srodrigc		    "#define\t%s_%s_ENABLED() \\\n"
517184696Srodrigc		    "\t__dtraceenabled_%s___%s(0)\n"
518184696Srodrigc		    "#endif\n",
519184696Srodrigc		    infop->dthi_pmname, mname,
520184696Srodrigc		    infop->dthi_pfname, fname,
521184696Srodrigc		    infop->dthi_pmname, mname,
522184696Srodrigc		    infop->dthi_pfname, fname) < 0)
523178479Sjb			return (dt_set_errno(dtp, errno));
524178479Sjb
525178479Sjb	} else {
526178479Sjb		if (fprintf(infop->dthi_out, "#define\t%s_%s_ENABLED() (0)\n",
527178479Sjb		    infop->dthi_pmname, mname) < 0)
528178479Sjb			return (dt_set_errno(dtp, errno));
529178479Sjb	}
530178479Sjb
531178479Sjb	return (0);
532178479Sjb}
533178479Sjb
534178479Sjbstatic int
535178479Sjbdt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out)
536178479Sjb{
537178479Sjb	dt_header_info_t info;
538178479Sjb	const char *p;
539178479Sjb	int i;
540178479Sjb
541178479Sjb	if (pvp->pv_flags & DT_PROVIDER_IMPL)
542178479Sjb		return (0);
543178479Sjb
544178479Sjb	/*
545178479Sjb	 * Count the instances of the '-' character since we'll need to double
546178479Sjb	 * those up.
547178479Sjb	 */
548178479Sjb	p = pvp->pv_desc.dtvd_name;
549178479Sjb	for (i = 0; (p = strchr(p, '-')) != NULL; i++)
550178479Sjb		p++;
551178479Sjb
552178479Sjb	info.dthi_dtp = dtp;
553178479Sjb	info.dthi_out = out;
554178479Sjb	info.dthi_empty = 0;
555178479Sjb
556178479Sjb	info.dthi_pmname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1);
557178479Sjb	dt_header_fmt_macro(info.dthi_pmname, pvp->pv_desc.dtvd_name);
558178479Sjb
559178479Sjb	info.dthi_pfname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1 + i);
560178479Sjb	dt_header_fmt_func(info.dthi_pfname, pvp->pv_desc.dtvd_name);
561178479Sjb
562212092Srpaulo#ifdef __FreeBSD__
563212092Srpaulo	if (fprintf(out, "#include <sys/sdt.h>\n\n") < 0)
564212092Srpaulo		return (dt_set_errno(dtp, errno));
565212092Srpaulo#endif
566178479Sjb	if (fprintf(out, "#if _DTRACE_VERSION\n\n") < 0)
567178479Sjb		return (dt_set_errno(dtp, errno));
568178479Sjb
569178479Sjb	if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
570178479Sjb		return (-1); /* dt_errno is set for us */
571178479Sjb	if (fprintf(out, "\n\n") < 0)
572178479Sjb		return (dt_set_errno(dtp, errno));
573178479Sjb	if (dt_idhash_iter(pvp->pv_probes, dt_header_decl, &info) != 0)
574178479Sjb		return (-1); /* dt_errno is set for us */
575178479Sjb
576178479Sjb	if (fprintf(out, "\n#else\n\n") < 0)
577178479Sjb		return (dt_set_errno(dtp, errno));
578178479Sjb
579178479Sjb	info.dthi_empty = 1;
580178479Sjb
581178479Sjb	if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
582178479Sjb		return (-1); /* dt_errno is set for us */
583178479Sjb
584178479Sjb	if (fprintf(out, "\n#endif\n\n") < 0)
585178479Sjb		return (dt_set_errno(dtp, errno));
586178479Sjb
587178479Sjb	return (0);
588178479Sjb}
589178479Sjb
590178479Sjbint
591178479Sjbdtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname)
592178479Sjb{
593178479Sjb	dt_provider_t *pvp;
594178479Sjb	char *mfname, *p;
595178479Sjb
596178479Sjb	if (fname != NULL) {
597178479Sjb		if ((p = strrchr(fname, '/')) != NULL)
598178479Sjb			fname = p + 1;
599178479Sjb
600178479Sjb		mfname = alloca(strlen(fname) + 1);
601178479Sjb		dt_header_fmt_macro(mfname, fname);
602178479Sjb		if (fprintf(out, "#ifndef\t_%s\n#define\t_%s\n\n",
603178479Sjb		    mfname, mfname) < 0)
604178479Sjb			return (dt_set_errno(dtp, errno));
605178479Sjb	}
606178479Sjb
607178479Sjb	if (fprintf(out, "#include <unistd.h>\n\n") < 0)
608178479Sjb		return (-1);
609178479Sjb
610178479Sjb	if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0)
611178479Sjb		return (-1);
612178479Sjb
613178479Sjb	for (pvp = dt_list_next(&dtp->dt_provlist);
614178479Sjb	    pvp != NULL; pvp = dt_list_next(pvp)) {
615178479Sjb		if (dt_header_provider(dtp, pvp, out) != 0)
616178479Sjb			return (-1); /* dt_errno is set for us */
617178479Sjb	}
618178479Sjb
619178479Sjb	if (fprintf(out, "\n#ifdef\t__cplusplus\n}\n#endif\n") < 0)
620178479Sjb		return (dt_set_errno(dtp, errno));
621178479Sjb
622178479Sjb	if (fname != NULL && fprintf(out, "\n#endif\t/* _%s */\n", mfname) < 0)
623178479Sjb		return (dt_set_errno(dtp, errno));
624178479Sjb
625178479Sjb	return (0);
626178479Sjb}
627