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