xref: /illumos-gate/usr/src/lib/libdtrace/common/dt_program.c (revision 1a7c1b724419d3cb5fa6eea75123c6b2060ba31b)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 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 
35 #include <dt_impl.h>
36 #include <dt_program.h>
37 #include <dt_printf.h>
38 
39 dtrace_prog_t *
40 dt_program_create(dtrace_hdl_t *dtp)
41 {
42 	dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t));
43 
44 	if (pgp != NULL)
45 		dt_list_append(&dtp->dt_programs, pgp);
46 	else
47 		(void) dt_set_errno(dtp, EDT_NOMEM);
48 
49 	return (pgp);
50 }
51 
52 void
53 dt_program_destroy(dtrace_hdl_t *dtp, dtrace_prog_t *pgp)
54 {
55 	dt_stmt_t *stp, *next;
56 	uint_t i;
57 
58 	for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
59 		next = dt_list_next(stp);
60 		dtrace_stmt_destroy(dtp, stp->ds_desc);
61 		dt_free(dtp, stp);
62 	}
63 
64 	for (i = 0; i < pgp->dp_xrefslen; i++)
65 		dt_free(dtp, pgp->dp_xrefs[i]);
66 
67 	dt_free(dtp, pgp->dp_xrefs);
68 	dt_list_delete(&dtp->dt_programs, pgp);
69 	dt_free(dtp, pgp);
70 }
71 
72 /*ARGSUSED*/
73 void
74 dtrace_program_info(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
75     dtrace_proginfo_t *pip)
76 {
77 	dt_stmt_t *stp;
78 	dtrace_actdesc_t *ap;
79 	dtrace_ecbdesc_t *last = NULL;
80 
81 	if (pip == NULL)
82 		return;
83 
84 	bzero(pip, sizeof (dtrace_proginfo_t));
85 
86 	if (dt_list_next(&pgp->dp_stmts) != NULL) {
87 		pip->dpi_descattr = _dtrace_maxattr;
88 		pip->dpi_stmtattr = _dtrace_maxattr;
89 	} else {
90 		pip->dpi_descattr = _dtrace_defattr;
91 		pip->dpi_stmtattr = _dtrace_defattr;
92 	}
93 
94 	for (stp = dt_list_next(&pgp->dp_stmts); stp; stp = dt_list_next(stp)) {
95 		dtrace_ecbdesc_t *edp = stp->ds_desc->dtsd_ecbdesc;
96 
97 		if (edp == last)
98 			continue;
99 		last = edp;
100 
101 		pip->dpi_descattr =
102 		    dt_attr_min(stp->ds_desc->dtsd_descattr, pip->dpi_descattr);
103 
104 		pip->dpi_stmtattr =
105 		    dt_attr_min(stp->ds_desc->dtsd_stmtattr, pip->dpi_stmtattr);
106 
107 		/*
108 		 * If there aren't any actions, account for the fact that
109 		 * recording the epid will generate a record.
110 		 */
111 		if (edp->dted_action == NULL)
112 			pip->dpi_recgens++;
113 
114 		for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
115 			if (ap->dtad_kind == DTRACEACT_SPECULATE) {
116 				pip->dpi_speculations++;
117 				continue;
118 			}
119 
120 			if (DTRACEACT_ISAGG(ap->dtad_kind)) {
121 				pip->dpi_recgens -= ap->dtad_arg;
122 				pip->dpi_aggregates++;
123 				continue;
124 			}
125 
126 			if (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind))
127 				continue;
128 
129 			if (ap->dtad_kind == DTRACEACT_DIFEXPR &&
130 			    ap->dtad_difo->dtdo_rtype.dtdt_kind ==
131 			    DIF_TYPE_CTF &&
132 			    ap->dtad_difo->dtdo_rtype.dtdt_size == 0)
133 				continue;
134 
135 			pip->dpi_recgens++;
136 		}
137 	}
138 }
139 
140 int
141 dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
142     dtrace_proginfo_t *pip)
143 {
144 	void *dof;
145 	int n, err;
146 
147 	dtrace_program_info(dtp, pgp, pip);
148 
149 	if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL)
150 		return (-1);
151 
152 	n = dt_ioctl(dtp, DTRACEIOC_ENABLE, dof);
153 	dtrace_dof_destroy(dtp, dof);
154 
155 	if (n == -1) {
156 		switch (errno) {
157 		case EINVAL:
158 			err = EDT_DIFINVAL;
159 			break;
160 		case EFAULT:
161 			err = EDT_DIFFAULT;
162 			break;
163 		case E2BIG:
164 			err = EDT_DIFSIZE;
165 			break;
166 		default:
167 			err = errno;
168 		}
169 
170 		return (dt_set_errno(dtp, err));
171 	}
172 
173 	if (pip != NULL)
174 		pip->dpi_matches += n;
175 
176 	return (0);
177 }
178 
179 static void
180 dt_ecbdesc_hold(dtrace_ecbdesc_t *edp)
181 {
182 	edp->dted_refcnt++;
183 }
184 
185 void
186 dt_ecbdesc_release(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
187 {
188 	if (--edp->dted_refcnt > 0)
189 		return;
190 
191 	dt_difo_free(dtp, edp->dted_pred.dtpdd_difo);
192 	assert(edp->dted_action == NULL);
193 	dt_free(dtp, edp);
194 }
195 
196 dtrace_ecbdesc_t *
197 dt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)
198 {
199 	dtrace_ecbdesc_t *edp;
200 
201 	if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) {
202 		(void) dt_set_errno(dtp, EDT_NOMEM);
203 		return (NULL);
204 	}
205 
206 	edp->dted_probe = *pdp;
207 	dt_ecbdesc_hold(edp);
208 	return (edp);
209 }
210 
211 dtrace_stmtdesc_t *
212 dtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
213 {
214 	dtrace_stmtdesc_t *sdp;
215 
216 	if ((sdp = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL)
217 		return (NULL);
218 
219 	dt_ecbdesc_hold(edp);
220 	sdp->dtsd_ecbdesc = edp;
221 	sdp->dtsd_descattr = _dtrace_defattr;
222 	sdp->dtsd_stmtattr = _dtrace_defattr;
223 
224 	return (sdp);
225 }
226 
227 dtrace_actdesc_t *
228 dtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
229 {
230 	dtrace_actdesc_t *new;
231 	dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
232 
233 	if ((new = dt_alloc(dtp, sizeof (dtrace_actdesc_t))) == NULL)
234 		return (NULL);
235 
236 	if (sdp->dtsd_action_last != NULL) {
237 		assert(sdp->dtsd_action != NULL);
238 		assert(sdp->dtsd_action_last->dtad_next == NULL);
239 		sdp->dtsd_action_last->dtad_next = new;
240 	} else {
241 		dtrace_actdesc_t *ap = edp->dted_action;
242 
243 		assert(sdp->dtsd_action == NULL);
244 		sdp->dtsd_action = new;
245 
246 		while (ap != NULL && ap->dtad_next != NULL)
247 			ap = ap->dtad_next;
248 
249 		if (ap == NULL)
250 			edp->dted_action = new;
251 		else
252 			ap->dtad_next = new;
253 	}
254 
255 	sdp->dtsd_action_last = new;
256 	bzero(new, sizeof (dtrace_actdesc_t));
257 	new->dtad_uarg = (uintptr_t)sdp;
258 
259 	return (new);
260 }
261 
262 int
263 dtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp)
264 {
265 	dt_stmt_t *stp = dt_alloc(dtp, sizeof (dt_stmt_t));
266 
267 	if (stp == NULL)
268 		return (-1); /* errno is set for us */
269 
270 	dt_list_append(&pgp->dp_stmts, stp);
271 	stp->ds_desc = sdp;
272 
273 	return (0);
274 }
275 
276 int
277 dtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
278     dtrace_stmt_f *func, void *data)
279 {
280 	dt_stmt_t *stp, *next;
281 	int status = 0;
282 
283 	for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
284 		next = dt_list_next(stp);
285 		if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0)
286 			break;
287 	}
288 
289 	return (status);
290 }
291 
292 void
293 dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
294 {
295 	dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
296 
297 	/*
298 	 * We need to remove any actions that we have on this ECB, and
299 	 * remove our hold on the ECB itself.
300 	 */
301 	if (sdp->dtsd_action != NULL) {
302 		dtrace_actdesc_t *last = sdp->dtsd_action_last;
303 		dtrace_actdesc_t *ap, *next;
304 
305 		assert(last != NULL);
306 
307 		for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
308 			if (ap == sdp->dtsd_action)
309 				break;
310 
311 			if (ap->dtad_next == sdp->dtsd_action)
312 				break;
313 		}
314 
315 		assert(ap != NULL);
316 
317 		if (ap == edp->dted_action)
318 			edp->dted_action = last->dtad_next;
319 		else
320 			ap->dtad_next = last->dtad_next;
321 
322 		/*
323 		 * We have now removed our action list from its ECB; we can
324 		 * safely destroy the list.
325 		 */
326 		last->dtad_next = NULL;
327 
328 		for (ap = sdp->dtsd_action; ap != NULL; ap = next) {
329 			assert(ap->dtad_uarg == (uintptr_t)sdp);
330 			dt_difo_free(dtp, ap->dtad_difo);
331 			next = ap->dtad_next;
332 			dt_free(dtp, ap);
333 		}
334 	}
335 
336 	if (sdp->dtsd_fmtdata != NULL)
337 		dt_printf_destroy(sdp->dtsd_fmtdata);
338 
339 	dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc);
340 	dt_free(dtp, sdp);
341 }
342