xref: /netbsd-src/external/cddl/osnet/dist/lib/libdtrace/common/dt_program.c (revision c0855460da148f19acba9384f3b92685f0354376)
1a864dc36Sdarran /*
2a864dc36Sdarran  * CDDL HEADER START
3a864dc36Sdarran  *
4a864dc36Sdarran  * The contents of this file are subject to the terms of the
5a864dc36Sdarran  * Common Development and Distribution License (the "License").
6a864dc36Sdarran  * You may not use this file except in compliance with the License.
7a864dc36Sdarran  *
8a864dc36Sdarran  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9a864dc36Sdarran  * or http://www.opensolaris.org/os/licensing.
10a864dc36Sdarran  * See the License for the specific language governing permissions
11a864dc36Sdarran  * and limitations under the License.
12a864dc36Sdarran  *
13a864dc36Sdarran  * When distributing Covered Code, include this CDDL HEADER in each
14a864dc36Sdarran  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15a864dc36Sdarran  * If applicable, add the following below this CDDL HEADER, with the
16a864dc36Sdarran  * fields enclosed by brackets "[]" replaced with your own identifying
17a864dc36Sdarran  * information: Portions Copyright [yyyy] [name of copyright owner]
18a864dc36Sdarran  *
19a864dc36Sdarran  * CDDL HEADER END
20a864dc36Sdarran  */
21a864dc36Sdarran 
22a864dc36Sdarran /*
23*c0855460Schristos  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24*c0855460Schristos  * Copyright (c) 2011 by Delphix. All rights reserved.
25a864dc36Sdarran  */
26a864dc36Sdarran 
27a864dc36Sdarran #include <unistd.h>
28a864dc36Sdarran #include <strings.h>
29a864dc36Sdarran #include <stdlib.h>
30a864dc36Sdarran #include <errno.h>
31a864dc36Sdarran #include <assert.h>
32a864dc36Sdarran #include <ctype.h>
33*c0855460Schristos #ifdef illumos
34a864dc36Sdarran #include <alloca.h>
35bb8023b5Sdarran #endif
36a864dc36Sdarran 
37a864dc36Sdarran #include <dt_impl.h>
38a864dc36Sdarran #include <dt_program.h>
39a864dc36Sdarran #include <dt_printf.h>
40a864dc36Sdarran #include <dt_provider.h>
41a864dc36Sdarran 
42a864dc36Sdarran dtrace_prog_t *
dt_program_create(dtrace_hdl_t * dtp)43a864dc36Sdarran dt_program_create(dtrace_hdl_t *dtp)
44a864dc36Sdarran {
45a864dc36Sdarran 	dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t));
46a864dc36Sdarran 
47*c0855460Schristos 	if (pgp != NULL) {
48a864dc36Sdarran 		dt_list_append(&dtp->dt_programs, pgp);
49*c0855460Schristos 	} else {
50a864dc36Sdarran 		(void) dt_set_errno(dtp, EDT_NOMEM);
51*c0855460Schristos 		return (NULL);
52*c0855460Schristos 	}
53a864dc36Sdarran 
54a864dc36Sdarran 	/*
55a864dc36Sdarran 	 * By default, programs start with DOF version 1 so that output files
56a864dc36Sdarran 	 * containing DOF are backward compatible. If a program requires new
57a864dc36Sdarran 	 * DOF features, the version is increased as needed.
58a864dc36Sdarran 	 */
59a864dc36Sdarran 	pgp->dp_dofversion = DOF_VERSION_1;
60a864dc36Sdarran 
61a864dc36Sdarran 	return (pgp);
62a864dc36Sdarran }
63a864dc36Sdarran 
64a864dc36Sdarran void
dt_program_destroy(dtrace_hdl_t * dtp,dtrace_prog_t * pgp)65a864dc36Sdarran dt_program_destroy(dtrace_hdl_t *dtp, dtrace_prog_t *pgp)
66a864dc36Sdarran {
67a864dc36Sdarran 	dt_stmt_t *stp, *next;
68a864dc36Sdarran 	uint_t i;
69a864dc36Sdarran 
70a864dc36Sdarran 	for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
71a864dc36Sdarran 		next = dt_list_next(stp);
72a864dc36Sdarran 		dtrace_stmt_destroy(dtp, stp->ds_desc);
73a864dc36Sdarran 		dt_free(dtp, stp);
74a864dc36Sdarran 	}
75a864dc36Sdarran 
76a864dc36Sdarran 	for (i = 0; i < pgp->dp_xrefslen; i++)
77a864dc36Sdarran 		dt_free(dtp, pgp->dp_xrefs[i]);
78a864dc36Sdarran 
79a864dc36Sdarran 	dt_free(dtp, pgp->dp_xrefs);
80a864dc36Sdarran 	dt_list_delete(&dtp->dt_programs, pgp);
81a864dc36Sdarran 	dt_free(dtp, pgp);
82a864dc36Sdarran }
83a864dc36Sdarran 
84a864dc36Sdarran /*ARGSUSED*/
85a864dc36Sdarran void
dtrace_program_info(dtrace_hdl_t * dtp,dtrace_prog_t * pgp,dtrace_proginfo_t * pip)86a864dc36Sdarran dtrace_program_info(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
87a864dc36Sdarran     dtrace_proginfo_t *pip)
88a864dc36Sdarran {
89a864dc36Sdarran 	dt_stmt_t *stp;
90a864dc36Sdarran 	dtrace_actdesc_t *ap;
91a864dc36Sdarran 	dtrace_ecbdesc_t *last = NULL;
92a864dc36Sdarran 
93a864dc36Sdarran 	if (pip == NULL)
94a864dc36Sdarran 		return;
95a864dc36Sdarran 
96a864dc36Sdarran 	bzero(pip, sizeof (dtrace_proginfo_t));
97a864dc36Sdarran 
98a864dc36Sdarran 	if (dt_list_next(&pgp->dp_stmts) != NULL) {
99a864dc36Sdarran 		pip->dpi_descattr = _dtrace_maxattr;
100a864dc36Sdarran 		pip->dpi_stmtattr = _dtrace_maxattr;
101a864dc36Sdarran 	} else {
102a864dc36Sdarran 		pip->dpi_descattr = _dtrace_defattr;
103a864dc36Sdarran 		pip->dpi_stmtattr = _dtrace_defattr;
104a864dc36Sdarran 	}
105a864dc36Sdarran 
106a864dc36Sdarran 	for (stp = dt_list_next(&pgp->dp_stmts); stp; stp = dt_list_next(stp)) {
107a864dc36Sdarran 		dtrace_ecbdesc_t *edp = stp->ds_desc->dtsd_ecbdesc;
108a864dc36Sdarran 
109a864dc36Sdarran 		if (edp == last)
110a864dc36Sdarran 			continue;
111a864dc36Sdarran 		last = edp;
112a864dc36Sdarran 
113a864dc36Sdarran 		pip->dpi_descattr =
114a864dc36Sdarran 		    dt_attr_min(stp->ds_desc->dtsd_descattr, pip->dpi_descattr);
115a864dc36Sdarran 
116a864dc36Sdarran 		pip->dpi_stmtattr =
117a864dc36Sdarran 		    dt_attr_min(stp->ds_desc->dtsd_stmtattr, pip->dpi_stmtattr);
118a864dc36Sdarran 
119a864dc36Sdarran 		/*
120a864dc36Sdarran 		 * If there aren't any actions, account for the fact that
121a864dc36Sdarran 		 * recording the epid will generate a record.
122a864dc36Sdarran 		 */
123a864dc36Sdarran 		if (edp->dted_action == NULL)
124a864dc36Sdarran 			pip->dpi_recgens++;
125a864dc36Sdarran 
126a864dc36Sdarran 		for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
127a864dc36Sdarran 			if (ap->dtad_kind == DTRACEACT_SPECULATE) {
128a864dc36Sdarran 				pip->dpi_speculations++;
129a864dc36Sdarran 				continue;
130a864dc36Sdarran 			}
131a864dc36Sdarran 
132a864dc36Sdarran 			if (DTRACEACT_ISAGG(ap->dtad_kind)) {
133a864dc36Sdarran 				pip->dpi_recgens -= ap->dtad_arg;
134a864dc36Sdarran 				pip->dpi_aggregates++;
135a864dc36Sdarran 				continue;
136a864dc36Sdarran 			}
137a864dc36Sdarran 
138a864dc36Sdarran 			if (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind))
139a864dc36Sdarran 				continue;
140a864dc36Sdarran 
141a864dc36Sdarran 			if (ap->dtad_kind == DTRACEACT_DIFEXPR &&
142a864dc36Sdarran 			    ap->dtad_difo->dtdo_rtype.dtdt_kind ==
143a864dc36Sdarran 			    DIF_TYPE_CTF &&
144a864dc36Sdarran 			    ap->dtad_difo->dtdo_rtype.dtdt_size == 0)
145a864dc36Sdarran 				continue;
146a864dc36Sdarran 
147a864dc36Sdarran 			pip->dpi_recgens++;
148a864dc36Sdarran 		}
149a864dc36Sdarran 	}
150a864dc36Sdarran }
151a864dc36Sdarran 
152a864dc36Sdarran int
dtrace_program_exec(dtrace_hdl_t * dtp,dtrace_prog_t * pgp,dtrace_proginfo_t * pip)153a864dc36Sdarran dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
154a864dc36Sdarran     dtrace_proginfo_t *pip)
155a864dc36Sdarran {
156bb8023b5Sdarran 	dtrace_enable_io_t args;
157a864dc36Sdarran 	void *dof;
158a864dc36Sdarran 	int n, err;
159a864dc36Sdarran 
160a864dc36Sdarran 	dtrace_program_info(dtp, pgp, pip);
161a864dc36Sdarran 
162a864dc36Sdarran 	if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL)
163a864dc36Sdarran 		return (-1);
164a864dc36Sdarran 
165bb8023b5Sdarran 	args.dof = dof;
166bb8023b5Sdarran 	args.n_matched = 0;
167bb8023b5Sdarran 	n = dt_ioctl(dtp, DTRACEIOC_ENABLE, &args);
168a864dc36Sdarran 	dtrace_dof_destroy(dtp, dof);
169a864dc36Sdarran 
170a864dc36Sdarran 	if (n == -1) {
171a864dc36Sdarran 		switch (errno) {
172a864dc36Sdarran 		case EINVAL:
173a864dc36Sdarran 			err = EDT_DIFINVAL;
174a864dc36Sdarran 			break;
175a864dc36Sdarran 		case EFAULT:
176a864dc36Sdarran 			err = EDT_DIFFAULT;
177a864dc36Sdarran 			break;
178a864dc36Sdarran 		case E2BIG:
179a864dc36Sdarran 			err = EDT_DIFSIZE;
180a864dc36Sdarran 			break;
181a252d550Shaad 		case EBUSY:
182a252d550Shaad 			err = EDT_ENABLING_ERR;
183a252d550Shaad 			break;
184a864dc36Sdarran 		default:
185a864dc36Sdarran 			err = errno;
186a864dc36Sdarran 		}
187a864dc36Sdarran 
188a864dc36Sdarran 		return (dt_set_errno(dtp, err));
189a864dc36Sdarran 	}
190a864dc36Sdarran 
191a864dc36Sdarran 	if (pip != NULL)
192bb8023b5Sdarran 		pip->dpi_matches += args.n_matched;
193a864dc36Sdarran 
194a864dc36Sdarran 	return (0);
195a864dc36Sdarran }
196a864dc36Sdarran 
197a864dc36Sdarran static void
dt_ecbdesc_hold(dtrace_ecbdesc_t * edp)198a864dc36Sdarran dt_ecbdesc_hold(dtrace_ecbdesc_t *edp)
199a864dc36Sdarran {
200a864dc36Sdarran 	edp->dted_refcnt++;
201a864dc36Sdarran }
202a864dc36Sdarran 
203a864dc36Sdarran void
dt_ecbdesc_release(dtrace_hdl_t * dtp,dtrace_ecbdesc_t * edp)204a864dc36Sdarran dt_ecbdesc_release(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
205a864dc36Sdarran {
206a864dc36Sdarran 	if (--edp->dted_refcnt > 0)
207a864dc36Sdarran 		return;
208a864dc36Sdarran 
209a864dc36Sdarran 	dt_difo_free(dtp, edp->dted_pred.dtpdd_difo);
210a864dc36Sdarran 	assert(edp->dted_action == NULL);
211a864dc36Sdarran 	dt_free(dtp, edp);
212a864dc36Sdarran }
213a864dc36Sdarran 
214a864dc36Sdarran dtrace_ecbdesc_t *
dt_ecbdesc_create(dtrace_hdl_t * dtp,const dtrace_probedesc_t * pdp)215a864dc36Sdarran dt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)
216a864dc36Sdarran {
217a864dc36Sdarran 	dtrace_ecbdesc_t *edp;
218a864dc36Sdarran 
219a864dc36Sdarran 	if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) {
220a864dc36Sdarran 		(void) dt_set_errno(dtp, EDT_NOMEM);
221a864dc36Sdarran 		return (NULL);
222a864dc36Sdarran 	}
223a864dc36Sdarran 
224a864dc36Sdarran 	edp->dted_probe = *pdp;
225a864dc36Sdarran 	dt_ecbdesc_hold(edp);
226a864dc36Sdarran 	return (edp);
227a864dc36Sdarran }
228a864dc36Sdarran 
229a864dc36Sdarran dtrace_stmtdesc_t *
dtrace_stmt_create(dtrace_hdl_t * dtp,dtrace_ecbdesc_t * edp)230a864dc36Sdarran dtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
231a864dc36Sdarran {
232a864dc36Sdarran 	dtrace_stmtdesc_t *sdp;
233a864dc36Sdarran 
234a864dc36Sdarran 	if ((sdp = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL)
235a864dc36Sdarran 		return (NULL);
236a864dc36Sdarran 
237a864dc36Sdarran 	dt_ecbdesc_hold(edp);
238a864dc36Sdarran 	sdp->dtsd_ecbdesc = edp;
239a864dc36Sdarran 	sdp->dtsd_descattr = _dtrace_defattr;
240a864dc36Sdarran 	sdp->dtsd_stmtattr = _dtrace_defattr;
241a864dc36Sdarran 
242a864dc36Sdarran 	return (sdp);
243a864dc36Sdarran }
244a864dc36Sdarran 
245a864dc36Sdarran dtrace_actdesc_t *
dtrace_stmt_action(dtrace_hdl_t * dtp,dtrace_stmtdesc_t * sdp)246a864dc36Sdarran dtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
247a864dc36Sdarran {
248a864dc36Sdarran 	dtrace_actdesc_t *new;
249a864dc36Sdarran 	dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
250a864dc36Sdarran 
251a864dc36Sdarran 	if ((new = dt_alloc(dtp, sizeof (dtrace_actdesc_t))) == NULL)
252a864dc36Sdarran 		return (NULL);
253a864dc36Sdarran 
254a864dc36Sdarran 	if (sdp->dtsd_action_last != NULL) {
255a864dc36Sdarran 		assert(sdp->dtsd_action != NULL);
256a864dc36Sdarran 		assert(sdp->dtsd_action_last->dtad_next == NULL);
257a864dc36Sdarran 		sdp->dtsd_action_last->dtad_next = new;
258a864dc36Sdarran 	} else {
259a864dc36Sdarran 		dtrace_actdesc_t *ap = edp->dted_action;
260a864dc36Sdarran 
261a864dc36Sdarran 		assert(sdp->dtsd_action == NULL);
262a864dc36Sdarran 		sdp->dtsd_action = new;
263a864dc36Sdarran 
264a864dc36Sdarran 		while (ap != NULL && ap->dtad_next != NULL)
265a864dc36Sdarran 			ap = ap->dtad_next;
266a864dc36Sdarran 
267a864dc36Sdarran 		if (ap == NULL)
268a864dc36Sdarran 			edp->dted_action = new;
269a864dc36Sdarran 		else
270a864dc36Sdarran 			ap->dtad_next = new;
271a864dc36Sdarran 	}
272a864dc36Sdarran 
273a864dc36Sdarran 	sdp->dtsd_action_last = new;
274a864dc36Sdarran 	bzero(new, sizeof (dtrace_actdesc_t));
275a864dc36Sdarran 	new->dtad_uarg = (uintptr_t)sdp;
276a864dc36Sdarran 
277a864dc36Sdarran 	return (new);
278a864dc36Sdarran }
279a864dc36Sdarran 
280a864dc36Sdarran int
dtrace_stmt_add(dtrace_hdl_t * dtp,dtrace_prog_t * pgp,dtrace_stmtdesc_t * sdp)281a864dc36Sdarran dtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp)
282a864dc36Sdarran {
283a864dc36Sdarran 	dt_stmt_t *stp = dt_alloc(dtp, sizeof (dt_stmt_t));
284a864dc36Sdarran 
285a864dc36Sdarran 	if (stp == NULL)
286a864dc36Sdarran 		return (-1); /* errno is set for us */
287a864dc36Sdarran 
288a864dc36Sdarran 	dt_list_append(&pgp->dp_stmts, stp);
289a864dc36Sdarran 	stp->ds_desc = sdp;
290a864dc36Sdarran 
291a864dc36Sdarran 	return (0);
292a864dc36Sdarran }
293a864dc36Sdarran 
294a864dc36Sdarran int
dtrace_stmt_iter(dtrace_hdl_t * dtp,dtrace_prog_t * pgp,dtrace_stmt_f * func,void * data)295a864dc36Sdarran dtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
296a864dc36Sdarran     dtrace_stmt_f *func, void *data)
297a864dc36Sdarran {
298a864dc36Sdarran 	dt_stmt_t *stp, *next;
299a864dc36Sdarran 	int status = 0;
300a864dc36Sdarran 
301a864dc36Sdarran 	for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
302a864dc36Sdarran 		next = dt_list_next(stp);
303a864dc36Sdarran 		if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0)
304a864dc36Sdarran 			break;
305a864dc36Sdarran 	}
306a864dc36Sdarran 
307a864dc36Sdarran 	return (status);
308a864dc36Sdarran }
309a864dc36Sdarran 
310a864dc36Sdarran void
dtrace_stmt_destroy(dtrace_hdl_t * dtp,dtrace_stmtdesc_t * sdp)311a864dc36Sdarran dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
312a864dc36Sdarran {
313a864dc36Sdarran 	dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
314a864dc36Sdarran 
315a864dc36Sdarran 	/*
316a864dc36Sdarran 	 * We need to remove any actions that we have on this ECB, and
317a864dc36Sdarran 	 * remove our hold on the ECB itself.
318a864dc36Sdarran 	 */
319a864dc36Sdarran 	if (sdp->dtsd_action != NULL) {
320a864dc36Sdarran 		dtrace_actdesc_t *last = sdp->dtsd_action_last;
321a864dc36Sdarran 		dtrace_actdesc_t *ap, *next;
322a864dc36Sdarran 
323a864dc36Sdarran 		assert(last != NULL);
324a864dc36Sdarran 
325a864dc36Sdarran 		for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
326a864dc36Sdarran 			if (ap == sdp->dtsd_action)
327a864dc36Sdarran 				break;
328a864dc36Sdarran 
329a864dc36Sdarran 			if (ap->dtad_next == sdp->dtsd_action)
330a864dc36Sdarran 				break;
331a864dc36Sdarran 		}
332a864dc36Sdarran 
333a864dc36Sdarran 		assert(ap != NULL);
334a864dc36Sdarran 
335a864dc36Sdarran 		if (ap == edp->dted_action)
336a864dc36Sdarran 			edp->dted_action = last->dtad_next;
337a864dc36Sdarran 		else
338a864dc36Sdarran 			ap->dtad_next = last->dtad_next;
339a864dc36Sdarran 
340a864dc36Sdarran 		/*
341a864dc36Sdarran 		 * We have now removed our action list from its ECB; we can
342a864dc36Sdarran 		 * safely destroy the list.
343a864dc36Sdarran 		 */
344a864dc36Sdarran 		last->dtad_next = NULL;
345a864dc36Sdarran 
346a864dc36Sdarran 		for (ap = sdp->dtsd_action; ap != NULL; ap = next) {
347a864dc36Sdarran 			assert(ap->dtad_uarg == (uintptr_t)sdp);
348a864dc36Sdarran 			dt_difo_free(dtp, ap->dtad_difo);
349a864dc36Sdarran 			next = ap->dtad_next;
350a864dc36Sdarran 			dt_free(dtp, ap);
351a864dc36Sdarran 		}
352a864dc36Sdarran 	}
353a864dc36Sdarran 
354a864dc36Sdarran 	if (sdp->dtsd_fmtdata != NULL)
355a864dc36Sdarran 		dt_printf_destroy(sdp->dtsd_fmtdata);
356*c0855460Schristos 	dt_free(dtp, sdp->dtsd_strdata);
357a864dc36Sdarran 
358a864dc36Sdarran 	dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc);
359a864dc36Sdarran 	dt_free(dtp, sdp);
360a864dc36Sdarran }
361a864dc36Sdarran 
362a864dc36Sdarran typedef struct dt_header_info {
363a864dc36Sdarran 	dtrace_hdl_t *dthi_dtp;	/* consumer handle */
364a864dc36Sdarran 	FILE *dthi_out;		/* output file */
365a864dc36Sdarran 	char *dthi_pmname;	/* provider macro name */
366a864dc36Sdarran 	char *dthi_pfname;	/* provider function name */
367a864dc36Sdarran 	int dthi_empty;		/* should we generate empty macros */
368a864dc36Sdarran } dt_header_info_t;
369a864dc36Sdarran 
370a864dc36Sdarran static void
dt_header_fmt_macro(char * buf,const char * str)371a864dc36Sdarran dt_header_fmt_macro(char *buf, const char *str)
372a864dc36Sdarran {
373a864dc36Sdarran 	for (;;) {
374b8c591baSchristos 		if (islower((unsigned char)*str)) {
375a864dc36Sdarran 			*buf++ = *str++ + 'A' - 'a';
376a864dc36Sdarran 		} else if (*str == '-') {
377a864dc36Sdarran 			*buf++ = '_';
378a864dc36Sdarran 			str++;
379a864dc36Sdarran 		} else if (*str == '.') {
380a864dc36Sdarran 			*buf++ = '_';
381a864dc36Sdarran 			str++;
382a864dc36Sdarran 		} else if ((*buf++ = *str++) == '\0') {
383a864dc36Sdarran 			break;
384a864dc36Sdarran 		}
385a864dc36Sdarran 	}
386a864dc36Sdarran }
387a864dc36Sdarran 
388a864dc36Sdarran static void
dt_header_fmt_func(char * buf,const char * str)389a864dc36Sdarran dt_header_fmt_func(char *buf, const char *str)
390a864dc36Sdarran {
391a864dc36Sdarran 	for (;;) {
392a864dc36Sdarran 		if (*str == '-') {
393a864dc36Sdarran 			*buf++ = '_';
394a864dc36Sdarran 			*buf++ = '_';
395a864dc36Sdarran 			str++;
396a864dc36Sdarran 		} else if ((*buf++ = *str++) == '\0') {
397a864dc36Sdarran 			break;
398a864dc36Sdarran 		}
399a864dc36Sdarran 	}
400a864dc36Sdarran }
401a864dc36Sdarran 
402a864dc36Sdarran /*ARGSUSED*/
403a864dc36Sdarran static int
dt_header_decl(dt_idhash_t * dhp,dt_ident_t * idp,void * data)404a864dc36Sdarran dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
405a864dc36Sdarran {
406a864dc36Sdarran 	dt_header_info_t *infop = data;
407a864dc36Sdarran 	dtrace_hdl_t *dtp = infop->dthi_dtp;
408a864dc36Sdarran 	dt_probe_t *prp = idp->di_data;
409a864dc36Sdarran 	dt_node_t *dnp;
410a864dc36Sdarran 	char buf[DT_TYPE_NAMELEN];
411a864dc36Sdarran 	char *fname;
412a864dc36Sdarran 	const char *p;
413a864dc36Sdarran 	int i;
414a864dc36Sdarran 
415a864dc36Sdarran 	p = prp->pr_name;
416a864dc36Sdarran 	for (i = 0; (p = strchr(p, '-')) != NULL; i++)
417a864dc36Sdarran 		p++;
418a864dc36Sdarran 
419a864dc36Sdarran 	fname = alloca(strlen(prp->pr_name) + 1 + i);
420a864dc36Sdarran 	dt_header_fmt_func(fname, prp->pr_name);
421a864dc36Sdarran 
422a864dc36Sdarran 	if (fprintf(infop->dthi_out, "extern void __dtrace_%s___%s(",
423a864dc36Sdarran 	    infop->dthi_pfname, fname) < 0)
424a864dc36Sdarran 		return (dt_set_errno(dtp, errno));
425a864dc36Sdarran 
426a864dc36Sdarran 	for (dnp = prp->pr_nargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) {
427a864dc36Sdarran 		if (fprintf(infop->dthi_out, "%s",
428a864dc36Sdarran 		    ctf_type_name(dnp->dn_ctfp, dnp->dn_type,
429a864dc36Sdarran 		    buf, sizeof (buf))) < 0)
430a864dc36Sdarran 			return (dt_set_errno(dtp, errno));
431a864dc36Sdarran 
432a864dc36Sdarran 		if (i + 1 != prp->pr_nargc &&
433a864dc36Sdarran 		    fprintf(infop->dthi_out, ", ") < 0)
434a864dc36Sdarran 			return (dt_set_errno(dtp, errno));
435a864dc36Sdarran 	}
436a864dc36Sdarran 
437a864dc36Sdarran 	if (i == 0 && fprintf(infop->dthi_out, "void") < 0)
438a864dc36Sdarran 		return (dt_set_errno(dtp, errno));
439a864dc36Sdarran 
440a864dc36Sdarran 	if (fprintf(infop->dthi_out, ");\n") < 0)
441a864dc36Sdarran 		return (dt_set_errno(dtp, errno));
442a864dc36Sdarran 
443a864dc36Sdarran 	if (fprintf(infop->dthi_out,
444a864dc36Sdarran 	    "#ifndef\t__sparc\n"
445a864dc36Sdarran 	    "extern int __dtraceenabled_%s___%s(void);\n"
446a864dc36Sdarran 	    "#else\n"
447a864dc36Sdarran 	    "extern int __dtraceenabled_%s___%s(long);\n"
448a864dc36Sdarran 	    "#endif\n",
449a864dc36Sdarran 	    infop->dthi_pfname, fname, infop->dthi_pfname, fname) < 0)
450a864dc36Sdarran 		return (dt_set_errno(dtp, errno));
451a864dc36Sdarran 
452a864dc36Sdarran 	return (0);
453a864dc36Sdarran }
454a864dc36Sdarran 
455a864dc36Sdarran /*ARGSUSED*/
456a864dc36Sdarran static int
dt_header_probe(dt_idhash_t * dhp,dt_ident_t * idp,void * data)457a864dc36Sdarran dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
458a864dc36Sdarran {
459a864dc36Sdarran 	dt_header_info_t *infop = data;
460a864dc36Sdarran 	dtrace_hdl_t *dtp = infop->dthi_dtp;
461a864dc36Sdarran 	dt_probe_t *prp = idp->di_data;
462a864dc36Sdarran 	char *mname, *fname;
463a864dc36Sdarran 	const char *p;
464a864dc36Sdarran 	int i;
465a864dc36Sdarran 
466a864dc36Sdarran 	p = prp->pr_name;
467a864dc36Sdarran 	for (i = 0; (p = strchr(p, '-')) != NULL; i++)
468a864dc36Sdarran 		p++;
469a864dc36Sdarran 
470a864dc36Sdarran 	mname = alloca(strlen(prp->pr_name) + 1);
471a864dc36Sdarran 	dt_header_fmt_macro(mname, prp->pr_name);
472a864dc36Sdarran 
473a864dc36Sdarran 	fname = alloca(strlen(prp->pr_name) + 1 + i);
474a864dc36Sdarran 	dt_header_fmt_func(fname, prp->pr_name);
475a864dc36Sdarran 
476a864dc36Sdarran 	if (fprintf(infop->dthi_out, "#define\t%s_%s(",
477a864dc36Sdarran 	    infop->dthi_pmname, mname) < 0)
478a864dc36Sdarran 		return (dt_set_errno(dtp, errno));
479a864dc36Sdarran 
480a864dc36Sdarran 	for (i = 0; i < prp->pr_nargc; i++) {
481a864dc36Sdarran 		if (fprintf(infop->dthi_out, "arg%d", i) < 0)
482a864dc36Sdarran 			return (dt_set_errno(dtp, errno));
483a864dc36Sdarran 
484a864dc36Sdarran 		if (i + 1 != prp->pr_nargc &&
485a864dc36Sdarran 		    fprintf(infop->dthi_out, ", ") < 0)
486a864dc36Sdarran 			return (dt_set_errno(dtp, errno));
487a864dc36Sdarran 	}
488a864dc36Sdarran 
489a864dc36Sdarran 	if (!infop->dthi_empty) {
490a864dc36Sdarran 		if (fprintf(infop->dthi_out, ") \\\n\t") < 0)
491a864dc36Sdarran 			return (dt_set_errno(dtp, errno));
492a864dc36Sdarran 
493a864dc36Sdarran 		if (fprintf(infop->dthi_out, "__dtrace_%s___%s(",
494a864dc36Sdarran 		    infop->dthi_pfname, fname) < 0)
495a864dc36Sdarran 			return (dt_set_errno(dtp, errno));
496a864dc36Sdarran 
497a864dc36Sdarran 		for (i = 0; i < prp->pr_nargc; i++) {
498a864dc36Sdarran 			if (fprintf(infop->dthi_out, "arg%d", i) < 0)
499a864dc36Sdarran 				return (dt_set_errno(dtp, errno));
500a864dc36Sdarran 
501a864dc36Sdarran 			if (i + 1 != prp->pr_nargc &&
502a864dc36Sdarran 			    fprintf(infop->dthi_out, ", ") < 0)
503a864dc36Sdarran 				return (dt_set_errno(dtp, errno));
504a864dc36Sdarran 		}
505a864dc36Sdarran 	}
506a864dc36Sdarran 
507a864dc36Sdarran 	if (fprintf(infop->dthi_out, ")\n") < 0)
508a864dc36Sdarran 		return (dt_set_errno(dtp, errno));
509a864dc36Sdarran 
510a864dc36Sdarran 	if (!infop->dthi_empty) {
511a864dc36Sdarran 		if (fprintf(infop->dthi_out,
512a864dc36Sdarran 		    "#ifndef\t__sparc\n"
513a864dc36Sdarran 		    "#define\t%s_%s_ENABLED() \\\n"
514a864dc36Sdarran 		    "\t__dtraceenabled_%s___%s()\n"
515a864dc36Sdarran 		    "#else\n"
516a864dc36Sdarran 		    "#define\t%s_%s_ENABLED() \\\n"
517a864dc36Sdarran 		    "\t__dtraceenabled_%s___%s(0)\n"
518a864dc36Sdarran 		    "#endif\n",
519a864dc36Sdarran 		    infop->dthi_pmname, mname,
520a864dc36Sdarran 		    infop->dthi_pfname, fname,
521a864dc36Sdarran 		    infop->dthi_pmname, mname,
522a864dc36Sdarran 		    infop->dthi_pfname, fname) < 0)
523a864dc36Sdarran 			return (dt_set_errno(dtp, errno));
524a864dc36Sdarran 
525a864dc36Sdarran 	} else {
526a864dc36Sdarran 		if (fprintf(infop->dthi_out, "#define\t%s_%s_ENABLED() (0)\n",
527a864dc36Sdarran 		    infop->dthi_pmname, mname) < 0)
528a864dc36Sdarran 			return (dt_set_errno(dtp, errno));
529a864dc36Sdarran 	}
530a864dc36Sdarran 
531a864dc36Sdarran 	return (0);
532a864dc36Sdarran }
533a864dc36Sdarran 
534a864dc36Sdarran static int
dt_header_provider(dtrace_hdl_t * dtp,dt_provider_t * pvp,FILE * out)535a864dc36Sdarran dt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out)
536a864dc36Sdarran {
537a864dc36Sdarran 	dt_header_info_t info;
538a864dc36Sdarran 	const char *p;
539a864dc36Sdarran 	int i;
540a864dc36Sdarran 
541a864dc36Sdarran 	if (pvp->pv_flags & DT_PROVIDER_IMPL)
542a864dc36Sdarran 		return (0);
543a864dc36Sdarran 
544a864dc36Sdarran 	/*
545a864dc36Sdarran 	 * Count the instances of the '-' character since we'll need to double
546a864dc36Sdarran 	 * those up.
547a864dc36Sdarran 	 */
548a864dc36Sdarran 	p = pvp->pv_desc.dtvd_name;
549a864dc36Sdarran 	for (i = 0; (p = strchr(p, '-')) != NULL; i++)
550a864dc36Sdarran 		p++;
551a864dc36Sdarran 
552a864dc36Sdarran 	info.dthi_dtp = dtp;
553a864dc36Sdarran 	info.dthi_out = out;
554a864dc36Sdarran 	info.dthi_empty = 0;
555a864dc36Sdarran 
556a864dc36Sdarran 	info.dthi_pmname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1);
557a864dc36Sdarran 	dt_header_fmt_macro(info.dthi_pmname, pvp->pv_desc.dtvd_name);
558a864dc36Sdarran 
559a864dc36Sdarran 	info.dthi_pfname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1 + i);
560a864dc36Sdarran 	dt_header_fmt_func(info.dthi_pfname, pvp->pv_desc.dtvd_name);
561a864dc36Sdarran 
562*c0855460Schristos #if defined(__FreeBSD__) || defined(__NetBSD__)
563*c0855460Schristos 	if (fprintf(out, "#include <sys/sdt.h>\n\n") < 0)
564*c0855460Schristos 		return (dt_set_errno(dtp, errno));
565*c0855460Schristos #endif
566a864dc36Sdarran 	if (fprintf(out, "#if _DTRACE_VERSION\n\n") < 0)
567a864dc36Sdarran 		return (dt_set_errno(dtp, errno));
568a864dc36Sdarran 
569a864dc36Sdarran 	if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
570a864dc36Sdarran 		return (-1); /* dt_errno is set for us */
571a864dc36Sdarran 	if (fprintf(out, "\n\n") < 0)
572a864dc36Sdarran 		return (dt_set_errno(dtp, errno));
573a864dc36Sdarran 	if (dt_idhash_iter(pvp->pv_probes, dt_header_decl, &info) != 0)
574a864dc36Sdarran 		return (-1); /* dt_errno is set for us */
575a864dc36Sdarran 
576a864dc36Sdarran 	if (fprintf(out, "\n#else\n\n") < 0)
577a864dc36Sdarran 		return (dt_set_errno(dtp, errno));
578a864dc36Sdarran 
579a864dc36Sdarran 	info.dthi_empty = 1;
580a864dc36Sdarran 
581a864dc36Sdarran 	if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
582a864dc36Sdarran 		return (-1); /* dt_errno is set for us */
583a864dc36Sdarran 
584a864dc36Sdarran 	if (fprintf(out, "\n#endif\n\n") < 0)
585a864dc36Sdarran 		return (dt_set_errno(dtp, errno));
586a864dc36Sdarran 
587a864dc36Sdarran 	return (0);
588a864dc36Sdarran }
589a864dc36Sdarran 
590a864dc36Sdarran int
dtrace_program_header(dtrace_hdl_t * dtp,FILE * out,const char * fname)591a864dc36Sdarran dtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname)
592a864dc36Sdarran {
593a864dc36Sdarran 	dt_provider_t *pvp;
594a864dc36Sdarran 	char *mfname, *p;
595a864dc36Sdarran 
596a864dc36Sdarran 	if (fname != NULL) {
597a864dc36Sdarran 		if ((p = strrchr(fname, '/')) != NULL)
598a864dc36Sdarran 			fname = p + 1;
599a864dc36Sdarran 
600a864dc36Sdarran 		mfname = alloca(strlen(fname) + 1);
601a864dc36Sdarran 		dt_header_fmt_macro(mfname, fname);
602a864dc36Sdarran 		if (fprintf(out, "#ifndef\t_%s\n#define\t_%s\n\n",
603a864dc36Sdarran 		    mfname, mfname) < 0)
604a864dc36Sdarran 			return (dt_set_errno(dtp, errno));
605a864dc36Sdarran 	}
606a864dc36Sdarran 
607a864dc36Sdarran 	if (fprintf(out, "#include <unistd.h>\n\n") < 0)
608a864dc36Sdarran 		return (-1);
609a864dc36Sdarran 
610a864dc36Sdarran 	if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0)
611a864dc36Sdarran 		return (-1);
612a864dc36Sdarran 
613a864dc36Sdarran 	for (pvp = dt_list_next(&dtp->dt_provlist);
614a864dc36Sdarran 	    pvp != NULL; pvp = dt_list_next(pvp)) {
615a864dc36Sdarran 		if (dt_header_provider(dtp, pvp, out) != 0)
616a864dc36Sdarran 			return (-1); /* dt_errno is set for us */
617a864dc36Sdarran 	}
618a864dc36Sdarran 
619a864dc36Sdarran 	if (fprintf(out, "\n#ifdef\t__cplusplus\n}\n#endif\n") < 0)
620a864dc36Sdarran 		return (dt_set_errno(dtp, errno));
621a864dc36Sdarran 
622a864dc36Sdarran 	if (fname != NULL && fprintf(out, "\n#endif\t/* _%s */\n", mfname) < 0)
623a864dc36Sdarran 		return (dt_set_errno(dtp, errno));
624a864dc36Sdarran 
625a864dc36Sdarran 	return (0);
626a864dc36Sdarran }
627