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