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