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