xref: /freebsd/cddl/contrib/opensolaris/lib/libdtrace/common/dt_program.c (revision 0b3105a37d7adcadcb720112fed4dc4e8040be99)
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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright (c) 2011 by Delphix. All rights reserved.
25  */
26 
27 #include <unistd.h>
28 #include <strings.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <assert.h>
32 #include <ctype.h>
33 #ifdef illumos
34 #include <alloca.h>
35 #endif
36 
37 #include <dt_impl.h>
38 #include <dt_program.h>
39 #include <dt_printf.h>
40 #include <dt_provider.h>
41 
42 dtrace_prog_t *
43 dt_program_create(dtrace_hdl_t *dtp)
44 {
45 	dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t));
46 
47 	if (pgp != NULL) {
48 		dt_list_append(&dtp->dt_programs, pgp);
49 	} else {
50 		(void) dt_set_errno(dtp, EDT_NOMEM);
51 		return (NULL);
52 	}
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 		case EBUSY:
182 			err = EDT_ENABLING_ERR;
183 			break;
184 		default:
185 			err = errno;
186 		}
187 
188 		return (dt_set_errno(dtp, err));
189 	}
190 
191 	if (pip != NULL)
192 		pip->dpi_matches += args.n_matched;
193 
194 	return (0);
195 }
196 
197 static void
198 dt_ecbdesc_hold(dtrace_ecbdesc_t *edp)
199 {
200 	edp->dted_refcnt++;
201 }
202 
203 void
204 dt_ecbdesc_release(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
205 {
206 	if (--edp->dted_refcnt > 0)
207 		return;
208 
209 	dt_difo_free(dtp, edp->dted_pred.dtpdd_difo);
210 	assert(edp->dted_action == NULL);
211 	dt_free(dtp, edp);
212 }
213 
214 dtrace_ecbdesc_t *
215 dt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)
216 {
217 	dtrace_ecbdesc_t *edp;
218 
219 	if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) {
220 		(void) dt_set_errno(dtp, EDT_NOMEM);
221 		return (NULL);
222 	}
223 
224 	edp->dted_probe = *pdp;
225 	dt_ecbdesc_hold(edp);
226 	return (edp);
227 }
228 
229 dtrace_stmtdesc_t *
230 dtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
231 {
232 	dtrace_stmtdesc_t *sdp;
233 
234 	if ((sdp = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL)
235 		return (NULL);
236 
237 	dt_ecbdesc_hold(edp);
238 	sdp->dtsd_ecbdesc = edp;
239 	sdp->dtsd_descattr = _dtrace_defattr;
240 	sdp->dtsd_stmtattr = _dtrace_defattr;
241 
242 	return (sdp);
243 }
244 
245 dtrace_actdesc_t *
246 dtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
247 {
248 	dtrace_actdesc_t *new;
249 	dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
250 
251 	if ((new = dt_alloc(dtp, sizeof (dtrace_actdesc_t))) == NULL)
252 		return (NULL);
253 
254 	if (sdp->dtsd_action_last != NULL) {
255 		assert(sdp->dtsd_action != NULL);
256 		assert(sdp->dtsd_action_last->dtad_next == NULL);
257 		sdp->dtsd_action_last->dtad_next = new;
258 	} else {
259 		dtrace_actdesc_t *ap = edp->dted_action;
260 
261 		assert(sdp->dtsd_action == NULL);
262 		sdp->dtsd_action = new;
263 
264 		while (ap != NULL && ap->dtad_next != NULL)
265 			ap = ap->dtad_next;
266 
267 		if (ap == NULL)
268 			edp->dted_action = new;
269 		else
270 			ap->dtad_next = new;
271 	}
272 
273 	sdp->dtsd_action_last = new;
274 	bzero(new, sizeof (dtrace_actdesc_t));
275 	new->dtad_uarg = (uintptr_t)sdp;
276 
277 	return (new);
278 }
279 
280 int
281 dtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp)
282 {
283 	dt_stmt_t *stp = dt_alloc(dtp, sizeof (dt_stmt_t));
284 
285 	if (stp == NULL)
286 		return (-1); /* errno is set for us */
287 
288 	dt_list_append(&pgp->dp_stmts, stp);
289 	stp->ds_desc = sdp;
290 
291 	return (0);
292 }
293 
294 int
295 dtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
296     dtrace_stmt_f *func, void *data)
297 {
298 	dt_stmt_t *stp, *next;
299 	int status = 0;
300 
301 	for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
302 		next = dt_list_next(stp);
303 		if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0)
304 			break;
305 	}
306 
307 	return (status);
308 }
309 
310 void
311 dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
312 {
313 	dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
314 
315 	/*
316 	 * We need to remove any actions that we have on this ECB, and
317 	 * remove our hold on the ECB itself.
318 	 */
319 	if (sdp->dtsd_action != NULL) {
320 		dtrace_actdesc_t *last = sdp->dtsd_action_last;
321 		dtrace_actdesc_t *ap, *next;
322 
323 		assert(last != NULL);
324 
325 		for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
326 			if (ap == sdp->dtsd_action)
327 				break;
328 
329 			if (ap->dtad_next == sdp->dtsd_action)
330 				break;
331 		}
332 
333 		assert(ap != NULL);
334 
335 		if (ap == edp->dted_action)
336 			edp->dted_action = last->dtad_next;
337 		else
338 			ap->dtad_next = last->dtad_next;
339 
340 		/*
341 		 * We have now removed our action list from its ECB; we can
342 		 * safely destroy the list.
343 		 */
344 		last->dtad_next = NULL;
345 
346 		for (ap = sdp->dtsd_action; ap != NULL; ap = next) {
347 			assert(ap->dtad_uarg == (uintptr_t)sdp);
348 			dt_difo_free(dtp, ap->dtad_difo);
349 			next = ap->dtad_next;
350 			dt_free(dtp, ap);
351 		}
352 	}
353 
354 	if (sdp->dtsd_fmtdata != NULL)
355 		dt_printf_destroy(sdp->dtsd_fmtdata);
356 	dt_free(dtp, sdp->dtsd_strdata);
357 
358 	dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc);
359 	dt_free(dtp, sdp);
360 }
361 
362 typedef struct dt_header_info {
363 	dtrace_hdl_t *dthi_dtp;	/* consumer handle */
364 	FILE *dthi_out;		/* output file */
365 	char *dthi_pmname;	/* provider macro name */
366 	char *dthi_pfname;	/* provider function name */
367 	int dthi_empty;		/* should we generate empty macros */
368 } dt_header_info_t;
369 
370 static void
371 dt_header_fmt_macro(char *buf, const char *str)
372 {
373 	for (;;) {
374 		if (islower(*str)) {
375 			*buf++ = *str++ + 'A' - 'a';
376 		} else if (*str == '-') {
377 			*buf++ = '_';
378 			str++;
379 		} else if (*str == '.') {
380 			*buf++ = '_';
381 			str++;
382 		} else if ((*buf++ = *str++) == '\0') {
383 			break;
384 		}
385 	}
386 }
387 
388 static void
389 dt_header_fmt_func(char *buf, const char *str)
390 {
391 	for (;;) {
392 		if (*str == '-') {
393 			*buf++ = '_';
394 			*buf++ = '_';
395 			str++;
396 		} else if ((*buf++ = *str++) == '\0') {
397 			break;
398 		}
399 	}
400 }
401 
402 /*ARGSUSED*/
403 static int
404 dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
405 {
406 	dt_header_info_t *infop = data;
407 	dtrace_hdl_t *dtp = infop->dthi_dtp;
408 	dt_probe_t *prp = idp->di_data;
409 	dt_node_t *dnp;
410 	char buf[DT_TYPE_NAMELEN];
411 	char *fname;
412 	const char *p;
413 	int i;
414 
415 	p = prp->pr_name;
416 	for (i = 0; (p = strchr(p, '-')) != NULL; i++)
417 		p++;
418 
419 	fname = alloca(strlen(prp->pr_name) + 1 + i);
420 	dt_header_fmt_func(fname, prp->pr_name);
421 
422 	if (fprintf(infop->dthi_out, "extern void __dtrace_%s___%s(",
423 	    infop->dthi_pfname, fname) < 0)
424 		return (dt_set_errno(dtp, errno));
425 
426 	for (dnp = prp->pr_nargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) {
427 		if (fprintf(infop->dthi_out, "%s",
428 		    ctf_type_name(dnp->dn_ctfp, dnp->dn_type,
429 		    buf, sizeof (buf))) < 0)
430 			return (dt_set_errno(dtp, errno));
431 
432 		if (i + 1 != prp->pr_nargc &&
433 		    fprintf(infop->dthi_out, ", ") < 0)
434 			return (dt_set_errno(dtp, errno));
435 	}
436 
437 	if (i == 0 && fprintf(infop->dthi_out, "void") < 0)
438 		return (dt_set_errno(dtp, errno));
439 
440 	if (fprintf(infop->dthi_out, ");\n") < 0)
441 		return (dt_set_errno(dtp, errno));
442 
443 	if (fprintf(infop->dthi_out,
444 	    "#ifndef\t__sparc\n"
445 	    "extern int __dtraceenabled_%s___%s(void);\n"
446 	    "#else\n"
447 	    "extern int __dtraceenabled_%s___%s(long);\n"
448 	    "#endif\n",
449 	    infop->dthi_pfname, fname, infop->dthi_pfname, fname) < 0)
450 		return (dt_set_errno(dtp, errno));
451 
452 	return (0);
453 }
454 
455 /*ARGSUSED*/
456 static int
457 dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
458 {
459 	dt_header_info_t *infop = data;
460 	dtrace_hdl_t *dtp = infop->dthi_dtp;
461 	dt_probe_t *prp = idp->di_data;
462 	char *mname, *fname;
463 	const char *p;
464 	int i;
465 
466 	p = prp->pr_name;
467 	for (i = 0; (p = strchr(p, '-')) != NULL; i++)
468 		p++;
469 
470 	mname = alloca(strlen(prp->pr_name) + 1);
471 	dt_header_fmt_macro(mname, prp->pr_name);
472 
473 	fname = alloca(strlen(prp->pr_name) + 1 + i);
474 	dt_header_fmt_func(fname, prp->pr_name);
475 
476 	if (fprintf(infop->dthi_out, "#define\t%s_%s(",
477 	    infop->dthi_pmname, mname) < 0)
478 		return (dt_set_errno(dtp, errno));
479 
480 	for (i = 0; i < prp->pr_nargc; i++) {
481 		if (fprintf(infop->dthi_out, "arg%d", i) < 0)
482 			return (dt_set_errno(dtp, errno));
483 
484 		if (i + 1 != prp->pr_nargc &&
485 		    fprintf(infop->dthi_out, ", ") < 0)
486 			return (dt_set_errno(dtp, errno));
487 	}
488 
489 	if (!infop->dthi_empty) {
490 		if (fprintf(infop->dthi_out, ") \\\n\t") < 0)
491 			return (dt_set_errno(dtp, errno));
492 
493 		if (fprintf(infop->dthi_out, "__dtrace_%s___%s(",
494 		    infop->dthi_pfname, fname) < 0)
495 			return (dt_set_errno(dtp, errno));
496 
497 		for (i = 0; i < prp->pr_nargc; i++) {
498 			if (fprintf(infop->dthi_out, "arg%d", i) < 0)
499 				return (dt_set_errno(dtp, errno));
500 
501 			if (i + 1 != prp->pr_nargc &&
502 			    fprintf(infop->dthi_out, ", ") < 0)
503 				return (dt_set_errno(dtp, errno));
504 		}
505 	}
506 
507 	if (fprintf(infop->dthi_out, ")\n") < 0)
508 		return (dt_set_errno(dtp, errno));
509 
510 	if (!infop->dthi_empty) {
511 		if (fprintf(infop->dthi_out,
512 		    "#ifndef\t__sparc\n"
513 		    "#define\t%s_%s_ENABLED() \\\n"
514 		    "\t__dtraceenabled_%s___%s()\n"
515 		    "#else\n"
516 		    "#define\t%s_%s_ENABLED() \\\n"
517 		    "\t__dtraceenabled_%s___%s(0)\n"
518 		    "#endif\n",
519 		    infop->dthi_pmname, mname,
520 		    infop->dthi_pfname, fname,
521 		    infop->dthi_pmname, mname,
522 		    infop->dthi_pfname, fname) < 0)
523 			return (dt_set_errno(dtp, errno));
524 
525 	} else {
526 		if (fprintf(infop->dthi_out, "#define\t%s_%s_ENABLED() (0)\n",
527 		    infop->dthi_pmname, mname) < 0)
528 			return (dt_set_errno(dtp, errno));
529 	}
530 
531 	return (0);
532 }
533 
534 static int
535 dt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out)
536 {
537 	dt_header_info_t info;
538 	const char *p;
539 	int i;
540 
541 	if (pvp->pv_flags & DT_PROVIDER_IMPL)
542 		return (0);
543 
544 	/*
545 	 * Count the instances of the '-' character since we'll need to double
546 	 * those up.
547 	 */
548 	p = pvp->pv_desc.dtvd_name;
549 	for (i = 0; (p = strchr(p, '-')) != NULL; i++)
550 		p++;
551 
552 	info.dthi_dtp = dtp;
553 	info.dthi_out = out;
554 	info.dthi_empty = 0;
555 
556 	info.dthi_pmname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1);
557 	dt_header_fmt_macro(info.dthi_pmname, pvp->pv_desc.dtvd_name);
558 
559 	info.dthi_pfname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1 + i);
560 	dt_header_fmt_func(info.dthi_pfname, pvp->pv_desc.dtvd_name);
561 
562 #ifdef __FreeBSD__
563 	if (fprintf(out, "#include <sys/sdt.h>\n\n") < 0)
564 		return (dt_set_errno(dtp, errno));
565 #endif
566 	if (fprintf(out, "#if _DTRACE_VERSION\n\n") < 0)
567 		return (dt_set_errno(dtp, errno));
568 
569 	if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
570 		return (-1); /* dt_errno is set for us */
571 	if (fprintf(out, "\n\n") < 0)
572 		return (dt_set_errno(dtp, errno));
573 	if (dt_idhash_iter(pvp->pv_probes, dt_header_decl, &info) != 0)
574 		return (-1); /* dt_errno is set for us */
575 
576 	if (fprintf(out, "\n#else\n\n") < 0)
577 		return (dt_set_errno(dtp, errno));
578 
579 	info.dthi_empty = 1;
580 
581 	if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
582 		return (-1); /* dt_errno is set for us */
583 
584 	if (fprintf(out, "\n#endif\n\n") < 0)
585 		return (dt_set_errno(dtp, errno));
586 
587 	return (0);
588 }
589 
590 int
591 dtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname)
592 {
593 	dt_provider_t *pvp;
594 	char *mfname, *p;
595 
596 	if (fname != NULL) {
597 		if ((p = strrchr(fname, '/')) != NULL)
598 			fname = p + 1;
599 
600 		mfname = alloca(strlen(fname) + 1);
601 		dt_header_fmt_macro(mfname, fname);
602 		if (fprintf(out, "#ifndef\t_%s\n#define\t_%s\n\n",
603 		    mfname, mfname) < 0)
604 			return (dt_set_errno(dtp, errno));
605 	}
606 
607 	if (fprintf(out, "#include <unistd.h>\n\n") < 0)
608 		return (-1);
609 
610 	if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0)
611 		return (-1);
612 
613 	for (pvp = dt_list_next(&dtp->dt_provlist);
614 	    pvp != NULL; pvp = dt_list_next(pvp)) {
615 		if (dt_header_provider(dtp, pvp, out) != 0)
616 			return (-1); /* dt_errno is set for us */
617 	}
618 
619 	if (fprintf(out, "\n#ifdef\t__cplusplus\n}\n#endif\n") < 0)
620 		return (dt_set_errno(dtp, errno));
621 
622 	if (fname != NULL && fprintf(out, "\n#endif\t/* _%s */\n", mfname) < 0)
623 		return (dt_set_errno(dtp, errno));
624 
625 	return (0);
626 }
627