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