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