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 <stdlib.h>
30 #include <strings.h>
31 #include <errno.h>
32 #include <unistd.h>
33 #include <assert.h>
34 
35 #include <dt_impl.h>
36 #include <dt_printf.h>
37 
38 static int
39 dt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id)
40 {
41 	dtrace_id_t max;
42 	int rval, i, maxformat;
43 	dtrace_eprobedesc_t *enabled, *nenabled;
44 	dtrace_probedesc_t *probe;
45 
46 	while (id >= (max = dtp->dt_maxprobe) || dtp->dt_pdesc == NULL) {
47 		dtrace_id_t new_max = max ? (max << 1) : 1;
48 		size_t nsize = new_max * sizeof (void *);
49 		dtrace_probedesc_t **new_pdesc;
50 		dtrace_eprobedesc_t **new_edesc;
51 
52 		if ((new_pdesc = malloc(nsize)) == NULL ||
53 		    (new_edesc = malloc(nsize)) == NULL) {
54 			free(new_pdesc);
55 			return (dt_set_errno(dtp, EDT_NOMEM));
56 		}
57 
58 		bzero(new_pdesc, nsize);
59 		bzero(new_edesc, nsize);
60 
61 		if (dtp->dt_pdesc != NULL) {
62 			size_t osize = max * sizeof (void *);
63 
64 			bcopy(dtp->dt_pdesc, new_pdesc, osize);
65 			free(dtp->dt_pdesc);
66 
67 			bcopy(dtp->dt_edesc, new_edesc, osize);
68 			free(dtp->dt_edesc);
69 		}
70 
71 		dtp->dt_pdesc = new_pdesc;
72 		dtp->dt_edesc = new_edesc;
73 		dtp->dt_maxprobe = new_max;
74 	}
75 
76 	if (dtp->dt_pdesc[id] != NULL)
77 		return (0);
78 
79 	if ((enabled = malloc(sizeof (dtrace_eprobedesc_t))) == NULL)
80 		return (dt_set_errno(dtp, EDT_NOMEM));
81 
82 	bzero(enabled, sizeof (dtrace_eprobedesc_t));
83 	enabled->dtepd_epid = id;
84 	enabled->dtepd_nrecs = 1;
85 
86 	if (dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled) == -1) {
87 		rval = dt_set_errno(dtp, errno);
88 		free(enabled);
89 		return (rval);
90 	}
91 
92 	if (DTRACE_SIZEOF_EPROBEDESC(enabled) != sizeof (*enabled)) {
93 		/*
94 		 * There must be more than one action.  Allocate the
95 		 * appropriate amount of space and try again.
96 		 */
97 		if ((nenabled =
98 		    malloc(DTRACE_SIZEOF_EPROBEDESC(enabled))) != NULL)
99 			bcopy(enabled, nenabled, sizeof (*enabled));
100 
101 		free(enabled);
102 
103 		if ((enabled = nenabled) == NULL)
104 			return (dt_set_errno(dtp, EDT_NOMEM));
105 
106 		rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled);
107 
108 		if (rval == -1) {
109 			rval = dt_set_errno(dtp, errno);
110 			free(enabled);
111 			return (rval);
112 		}
113 	}
114 
115 	if ((probe = malloc(sizeof (dtrace_probedesc_t))) == NULL) {
116 		free(enabled);
117 		return (dt_set_errno(dtp, EDT_NOMEM));
118 	}
119 
120 	probe->dtpd_id = enabled->dtepd_probeid;
121 
122 	if (dt_ioctl(dtp, DTRACEIOC_PROBES, probe) == -1) {
123 		rval = dt_set_errno(dtp, errno);
124 		goto err;
125 	}
126 
127 	for (i = 0; i < enabled->dtepd_nrecs; i++) {
128 		dtrace_fmtdesc_t fmt;
129 		dtrace_recdesc_t *rec = &enabled->dtepd_rec[i];
130 
131 		if (!DTRACEACT_ISPRINTFLIKE(rec->dtrd_action))
132 			continue;
133 
134 		if (rec->dtrd_format == 0)
135 			continue;
136 
137 		if (rec->dtrd_format <= dtp->dt_maxformat &&
138 		    dtp->dt_formats[rec->dtrd_format - 1] != NULL)
139 			continue;
140 
141 		bzero(&fmt, sizeof (fmt));
142 		fmt.dtfd_format = rec->dtrd_format;
143 		fmt.dtfd_string = NULL;
144 		fmt.dtfd_length = 0;
145 
146 		if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
147 			rval = dt_set_errno(dtp, errno);
148 			goto err;
149 		}
150 
151 		if ((fmt.dtfd_string = malloc(fmt.dtfd_length)) == NULL) {
152 			rval = dt_set_errno(dtp, EDT_NOMEM);
153 			goto err;
154 		}
155 
156 		if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
157 			rval = dt_set_errno(dtp, errno);
158 			free(fmt.dtfd_string);
159 			goto err;
160 		}
161 
162 		while (rec->dtrd_format > (maxformat = dtp->dt_maxformat)) {
163 			int new_max = maxformat ? (maxformat << 1) : 1;
164 			size_t nsize = new_max * sizeof (void *);
165 			size_t osize = maxformat * sizeof (void *);
166 			void **new_formats = malloc(nsize);
167 
168 			if (new_formats == NULL) {
169 				rval = dt_set_errno(dtp, EDT_NOMEM);
170 				free(fmt.dtfd_string);
171 				goto err;
172 			}
173 
174 			bzero(new_formats, nsize);
175 			bcopy(dtp->dt_formats, new_formats, osize);
176 			free(dtp->dt_formats);
177 
178 			dtp->dt_formats = new_formats;
179 			dtp->dt_maxformat = new_max;
180 		}
181 
182 		dtp->dt_formats[rec->dtrd_format - 1] =
183 		    rec->dtrd_action == DTRACEACT_PRINTA ?
184 		    dtrace_printa_create(dtp, fmt.dtfd_string) :
185 		    dtrace_printf_create(dtp, fmt.dtfd_string);
186 
187 		free(fmt.dtfd_string);
188 
189 		if (dtp->dt_formats[rec->dtrd_format - 1] == NULL) {
190 			rval = -1; /* dt_errno is set for us */
191 			goto err;
192 		}
193 	}
194 
195 	dtp->dt_pdesc[id] = probe;
196 	dtp->dt_edesc[id] = enabled;
197 
198 	return (0);
199 
200 err:
201 	/*
202 	 * If we failed, free our allocated probes.  Note that if we failed
203 	 * while allocating formats, we aren't going to free formats that
204 	 * we have already allocated.  This is okay; these formats are
205 	 * hanging off of dt_formats and will therefore not be leaked.
206 	 */
207 	free(enabled);
208 	free(probe);
209 	return (rval);
210 }
211 
212 int
213 dt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid,
214     dtrace_eprobedesc_t **epdp, dtrace_probedesc_t **pdp)
215 {
216 	int rval;
217 
218 	if (epid >= dtp->dt_maxprobe || dtp->dt_pdesc[epid] == NULL) {
219 		if ((rval = dt_epid_add(dtp, epid)) != 0)
220 			return (rval);
221 	}
222 
223 	assert(epid < dtp->dt_maxprobe);
224 	assert(dtp->dt_edesc[epid] != NULL);
225 	assert(dtp->dt_pdesc[epid] != NULL);
226 	*epdp = dtp->dt_edesc[epid];
227 	*pdp = dtp->dt_pdesc[epid];
228 
229 	return (0);
230 }
231 
232 void
233 dt_epid_destroy(dtrace_hdl_t *dtp)
234 {
235 	size_t i;
236 
237 	assert((dtp->dt_pdesc != NULL && dtp->dt_edesc != NULL &&
238 	    dtp->dt_maxprobe > 0) || (dtp->dt_pdesc == NULL &&
239 	    dtp->dt_edesc == NULL && dtp->dt_maxprobe == 0));
240 
241 	if (dtp->dt_pdesc == NULL)
242 		return;
243 
244 	for (i = 0; i < dtp->dt_maxprobe; i++) {
245 		if (dtp->dt_edesc[i] == NULL) {
246 			assert(dtp->dt_pdesc[i] == NULL);
247 			continue;
248 		}
249 
250 		assert(dtp->dt_pdesc[i] != NULL);
251 		free(dtp->dt_edesc[i]);
252 		free(dtp->dt_pdesc[i]);
253 	}
254 
255 	free(dtp->dt_pdesc);
256 	dtp->dt_pdesc = NULL;
257 
258 	free(dtp->dt_edesc);
259 	dtp->dt_edesc = NULL;
260 	dtp->dt_maxprobe = 0;
261 }
262 
263 void *
264 dt_format_lookup(dtrace_hdl_t *dtp, int format)
265 {
266 	if (format == 0 || format > dtp->dt_maxformat)
267 		return (NULL);
268 
269 	if (dtp->dt_formats == NULL)
270 		return (NULL);
271 
272 	return (dtp->dt_formats[format - 1]);
273 }
274 
275 void
276 dt_format_destroy(dtrace_hdl_t *dtp)
277 {
278 	int i;
279 
280 	for (i = 0; i < dtp->dt_maxformat; i++) {
281 		if (dtp->dt_formats[i] != NULL)
282 			dt_printf_destroy(dtp->dt_formats[i]);
283 	}
284 
285 	free(dtp->dt_formats);
286 	dtp->dt_formats = NULL;
287 }
288 
289 static int
290 dt_aggid_add(dtrace_hdl_t *dtp, dtrace_aggid_t id)
291 {
292 	dtrace_id_t max;
293 	dtrace_epid_t epid;
294 	int rval;
295 
296 	while (id >= (max = dtp->dt_maxagg) || dtp->dt_aggdesc == NULL) {
297 		dtrace_id_t new_max = max ? (max << 1) : 1;
298 		size_t nsize = new_max * sizeof (void *);
299 		dtrace_aggdesc_t **new_aggdesc;
300 
301 		if ((new_aggdesc = malloc(nsize)) == NULL)
302 			return (dt_set_errno(dtp, EDT_NOMEM));
303 
304 		bzero(new_aggdesc, nsize);
305 
306 		if (dtp->dt_aggdesc != NULL) {
307 			bcopy(dtp->dt_aggdesc, new_aggdesc,
308 			    max * sizeof (void *));
309 			free(dtp->dt_aggdesc);
310 		}
311 
312 		dtp->dt_aggdesc = new_aggdesc;
313 		dtp->dt_maxagg = new_max;
314 	}
315 
316 	if (dtp->dt_aggdesc[id] == NULL) {
317 		dtrace_aggdesc_t *agg, *nagg;
318 
319 		if ((agg = malloc(sizeof (dtrace_aggdesc_t))) == NULL)
320 			return (dt_set_errno(dtp, EDT_NOMEM));
321 
322 		bzero(agg, sizeof (dtrace_aggdesc_t));
323 		agg->dtagd_id = id;
324 		agg->dtagd_nrecs = 1;
325 
326 		if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg) == -1) {
327 			rval = dt_set_errno(dtp, errno);
328 			free(agg);
329 			return (rval);
330 		}
331 
332 		if (DTRACE_SIZEOF_AGGDESC(agg) != sizeof (*agg)) {
333 			/*
334 			 * There must be more than one action.  Allocate the
335 			 * appropriate amount of space and try again.
336 			 */
337 			if ((nagg = malloc(DTRACE_SIZEOF_AGGDESC(agg))) != NULL)
338 				bcopy(agg, nagg, sizeof (*agg));
339 
340 			free(agg);
341 
342 			if ((agg = nagg) == NULL)
343 				return (dt_set_errno(dtp, EDT_NOMEM));
344 
345 			rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg);
346 
347 			if (rval == -1) {
348 				rval = dt_set_errno(dtp, errno);
349 				free(agg);
350 				return (rval);
351 			}
352 		}
353 
354 		/*
355 		 * If we have a uarg, it's a pointer to the compiler-generated
356 		 * statement; we'll use this value to get the name and
357 		 * compiler-generated variable ID for the aggregation.  If
358 		 * we're grabbing an anonymous enabling, this pointer value
359 		 * is obviously meaningless -- and in this case, we can't
360 		 * provide the compiler-generated aggregation information.
361 		 */
362 		if (dtp->dt_options[DTRACEOPT_GRABANON] == DTRACEOPT_UNSET) {
363 			dtrace_stmtdesc_t *sdp;
364 			dt_ident_t *aid;
365 
366 			sdp = (dtrace_stmtdesc_t *)(uintptr_t)
367 			    agg->dtagd_rec[0].dtrd_uarg;
368 			aid = sdp->dtsd_aggdata;
369 			agg->dtagd_name = aid->di_name;
370 			agg->dtagd_varid = aid->di_id;
371 		} else {
372 			agg->dtagd_varid = DTRACE_AGGVARIDNONE;
373 		}
374 
375 		if ((epid = agg->dtagd_epid) >= dtp->dt_maxprobe ||
376 		    dtp->dt_pdesc[epid] == NULL) {
377 			if ((rval = dt_epid_add(dtp, epid)) != 0) {
378 				free(agg);
379 				return (rval);
380 			}
381 		}
382 
383 		dtp->dt_aggdesc[id] = agg;
384 	}
385 
386 	return (0);
387 }
388 
389 int
390 dt_aggid_lookup(dtrace_hdl_t *dtp, dtrace_aggid_t aggid,
391     dtrace_aggdesc_t **adp)
392 {
393 	int rval;
394 
395 	if (aggid >= dtp->dt_maxagg || dtp->dt_aggdesc[aggid] == NULL) {
396 		if ((rval = dt_aggid_add(dtp, aggid)) != 0)
397 			return (rval);
398 	}
399 
400 	assert(aggid < dtp->dt_maxagg);
401 	assert(dtp->dt_aggdesc[aggid] != NULL);
402 	*adp = dtp->dt_aggdesc[aggid];
403 
404 	return (0);
405 }
406 
407 void
408 dt_aggid_destroy(dtrace_hdl_t *dtp)
409 {
410 	size_t i;
411 
412 	assert((dtp->dt_aggdesc != NULL && dtp->dt_maxagg != 0) ||
413 	    (dtp->dt_aggdesc == NULL && dtp->dt_maxagg == 0));
414 
415 	if (dtp->dt_aggdesc == NULL)
416 		return;
417 
418 	for (i = 0; i < dtp->dt_maxagg; i++) {
419 		if (dtp->dt_aggdesc[i] != NULL)
420 			free(dtp->dt_aggdesc[i]);
421 	}
422 
423 	free(dtp->dt_aggdesc);
424 	dtp->dt_aggdesc = NULL;
425 	dtp->dt_maxagg = 0;
426 }
427