xref: /illumos-gate/usr/src/lib/libdtrace/common/dt_map.c (revision 069e6b7e31ba5dcbc5441b98af272714d9a5455c)
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 (dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled) == -1) {
159 		rval = dt_set_errno(dtp, errno);
160 		free(enabled);
161 		return (rval);
162 	}
163 
164 	if (DTRACE_SIZEOF_EPROBEDESC(enabled) != sizeof (*enabled)) {
165 		/*
166 		 * There must be more than one action.  Allocate the
167 		 * appropriate amount of space and try again.
168 		 */
169 		if ((nenabled =
170 		    malloc(DTRACE_SIZEOF_EPROBEDESC(enabled))) != NULL)
171 			bcopy(enabled, nenabled, sizeof (*enabled));
172 
173 		free(enabled);
174 
175 		if ((enabled = nenabled) == NULL)
176 			return (dt_set_errno(dtp, EDT_NOMEM));
177 
178 		rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled);
179 
180 		if (rval == -1) {
181 			rval = dt_set_errno(dtp, errno);
182 			free(enabled);
183 			return (rval);
184 		}
185 	}
186 
187 	if ((probe = malloc(sizeof (dtrace_probedesc_t))) == NULL) {
188 		free(enabled);
189 		return (dt_set_errno(dtp, EDT_NOMEM));
190 	}
191 
192 	probe->dtpd_id = enabled->dtepd_probeid;
193 
194 	if (dt_ioctl(dtp, DTRACEIOC_PROBES, probe) == -1) {
195 		rval = dt_set_errno(dtp, errno);
196 		goto err;
197 	}
198 
199 	for (i = 0; i < enabled->dtepd_nrecs; i++) {
200 		dtrace_recdesc_t *rec = &enabled->dtepd_rec[i];
201 
202 		if (DTRACEACT_ISPRINTFLIKE(rec->dtrd_action)) {
203 			if (dt_strdata_add(dtp, rec, &dtp->dt_formats,
204 			    &dtp->dt_maxformat) != 0) {
205 				rval = -1;
206 				goto err;
207 			}
208 		} else if (rec->dtrd_action == DTRACEACT_DIFEXPR) {
209 			if (dt_strdata_add(dtp, rec,
210 			    (void ***)&dtp->dt_strdata,
211 			    &dtp->dt_maxstrdata) != 0) {
212 				rval = -1;
213 				goto err;
214 			}
215 		}
216 
217 	}
218 
219 	dtp->dt_pdesc[id] = probe;
220 	dtp->dt_edesc[id] = enabled;
221 
222 	return (0);
223 
224 err:
225 	/*
226 	 * If we failed, free our allocated probes.  Note that if we failed
227 	 * while allocating formats, we aren't going to free formats that
228 	 * we have already allocated.  This is okay; these formats are
229 	 * hanging off of dt_formats and will therefore not be leaked.
230 	 */
231 	free(enabled);
232 	free(probe);
233 	return (rval);
234 }
235 
236 int
237 dt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid,
238     dtrace_eprobedesc_t **epdp, dtrace_probedesc_t **pdp)
239 {
240 	int rval;
241 
242 	if (epid >= dtp->dt_maxprobe || dtp->dt_pdesc[epid] == NULL) {
243 		if ((rval = dt_epid_add(dtp, epid)) != 0)
244 			return (rval);
245 	}
246 
247 	assert(epid < dtp->dt_maxprobe);
248 	assert(dtp->dt_edesc[epid] != NULL);
249 	assert(dtp->dt_pdesc[epid] != NULL);
250 	*epdp = dtp->dt_edesc[epid];
251 	*pdp = dtp->dt_pdesc[epid];
252 
253 	return (0);
254 }
255 
256 void
257 dt_epid_destroy(dtrace_hdl_t *dtp)
258 {
259 	size_t i;
260 
261 	assert((dtp->dt_pdesc != NULL && dtp->dt_edesc != NULL &&
262 	    dtp->dt_maxprobe > 0) || (dtp->dt_pdesc == NULL &&
263 	    dtp->dt_edesc == NULL && dtp->dt_maxprobe == 0));
264 
265 	if (dtp->dt_pdesc == NULL)
266 		return;
267 
268 	for (i = 0; i < dtp->dt_maxprobe; i++) {
269 		if (dtp->dt_edesc[i] == NULL) {
270 			assert(dtp->dt_pdesc[i] == NULL);
271 			continue;
272 		}
273 
274 		assert(dtp->dt_pdesc[i] != NULL);
275 		free(dtp->dt_edesc[i]);
276 		free(dtp->dt_pdesc[i]);
277 	}
278 
279 	free(dtp->dt_pdesc);
280 	dtp->dt_pdesc = NULL;
281 
282 	free(dtp->dt_edesc);
283 	dtp->dt_edesc = NULL;
284 	dtp->dt_maxprobe = 0;
285 }
286 
287 void *
288 dt_format_lookup(dtrace_hdl_t *dtp, int format)
289 {
290 	if (format == 0 || format > dtp->dt_maxformat)
291 		return (NULL);
292 
293 	if (dtp->dt_formats == NULL)
294 		return (NULL);
295 
296 	return (dtp->dt_formats[format - 1]);
297 }
298 
299 void
300 dt_format_destroy(dtrace_hdl_t *dtp)
301 {
302 	int i;
303 
304 	for (i = 0; i < dtp->dt_maxformat; i++) {
305 		if (dtp->dt_formats[i] != NULL)
306 			dt_printf_destroy(dtp->dt_formats[i]);
307 	}
308 
309 	free(dtp->dt_formats);
310 	dtp->dt_formats = NULL;
311 }
312 
313 static int
314 dt_aggid_add(dtrace_hdl_t *dtp, dtrace_aggid_t id)
315 {
316 	dtrace_id_t max;
317 	dtrace_epid_t epid;
318 	int rval;
319 
320 	while (id >= (max = dtp->dt_maxagg) || dtp->dt_aggdesc == NULL) {
321 		dtrace_id_t new_max = max ? (max << 1) : 1;
322 		size_t nsize = new_max * sizeof (void *);
323 		dtrace_aggdesc_t **new_aggdesc;
324 
325 		if ((new_aggdesc = malloc(nsize)) == NULL)
326 			return (dt_set_errno(dtp, EDT_NOMEM));
327 
328 		bzero(new_aggdesc, nsize);
329 
330 		if (dtp->dt_aggdesc != NULL) {
331 			bcopy(dtp->dt_aggdesc, new_aggdesc,
332 			    max * sizeof (void *));
333 			free(dtp->dt_aggdesc);
334 		}
335 
336 		dtp->dt_aggdesc = new_aggdesc;
337 		dtp->dt_maxagg = new_max;
338 	}
339 
340 	if (dtp->dt_aggdesc[id] == NULL) {
341 		dtrace_aggdesc_t *agg, *nagg;
342 
343 		if ((agg = malloc(sizeof (dtrace_aggdesc_t))) == NULL)
344 			return (dt_set_errno(dtp, EDT_NOMEM));
345 
346 		bzero(agg, sizeof (dtrace_aggdesc_t));
347 		agg->dtagd_id = id;
348 		agg->dtagd_nrecs = 1;
349 
350 		if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg) == -1) {
351 			rval = dt_set_errno(dtp, errno);
352 			free(agg);
353 			return (rval);
354 		}
355 
356 		if (DTRACE_SIZEOF_AGGDESC(agg) != sizeof (*agg)) {
357 			/*
358 			 * There must be more than one action.  Allocate the
359 			 * appropriate amount of space and try again.
360 			 */
361 			if ((nagg = malloc(DTRACE_SIZEOF_AGGDESC(agg))) != NULL)
362 				bcopy(agg, nagg, sizeof (*agg));
363 
364 			free(agg);
365 
366 			if ((agg = nagg) == NULL)
367 				return (dt_set_errno(dtp, EDT_NOMEM));
368 
369 			rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg);
370 
371 			if (rval == -1) {
372 				rval = dt_set_errno(dtp, errno);
373 				free(agg);
374 				return (rval);
375 			}
376 		}
377 
378 		/*
379 		 * If we have a uarg, it's a pointer to the compiler-generated
380 		 * statement; we'll use this value to get the name and
381 		 * compiler-generated variable ID for the aggregation.  If
382 		 * we're grabbing an anonymous enabling, this pointer value
383 		 * is obviously meaningless -- and in this case, we can't
384 		 * provide the compiler-generated aggregation information.
385 		 */
386 		if (dtp->dt_options[DTRACEOPT_GRABANON] == DTRACEOPT_UNSET &&
387 		    agg->dtagd_rec[0].dtrd_uarg != 0) {
388 			dtrace_stmtdesc_t *sdp;
389 			dt_ident_t *aid;
390 
391 			sdp = (dtrace_stmtdesc_t *)(uintptr_t)
392 			    agg->dtagd_rec[0].dtrd_uarg;
393 			aid = sdp->dtsd_aggdata;
394 			agg->dtagd_name = aid->di_name;
395 			agg->dtagd_varid = aid->di_id;
396 		} else {
397 			agg->dtagd_varid = DTRACE_AGGVARIDNONE;
398 		}
399 
400 		if ((epid = agg->dtagd_epid) >= dtp->dt_maxprobe ||
401 		    dtp->dt_pdesc[epid] == NULL) {
402 			if ((rval = dt_epid_add(dtp, epid)) != 0) {
403 				free(agg);
404 				return (rval);
405 			}
406 		}
407 
408 		dtp->dt_aggdesc[id] = agg;
409 	}
410 
411 	return (0);
412 }
413 
414 int
415 dt_aggid_lookup(dtrace_hdl_t *dtp, dtrace_aggid_t aggid,
416     dtrace_aggdesc_t **adp)
417 {
418 	int rval;
419 
420 	if (aggid >= dtp->dt_maxagg || dtp->dt_aggdesc[aggid] == NULL) {
421 		if ((rval = dt_aggid_add(dtp, aggid)) != 0)
422 			return (rval);
423 	}
424 
425 	assert(aggid < dtp->dt_maxagg);
426 	assert(dtp->dt_aggdesc[aggid] != NULL);
427 	*adp = dtp->dt_aggdesc[aggid];
428 
429 	return (0);
430 }
431 
432 void
433 dt_aggid_destroy(dtrace_hdl_t *dtp)
434 {
435 	size_t i;
436 
437 	assert((dtp->dt_aggdesc != NULL && dtp->dt_maxagg != 0) ||
438 	    (dtp->dt_aggdesc == NULL && dtp->dt_maxagg == 0));
439 
440 	if (dtp->dt_aggdesc == NULL)
441 		return;
442 
443 	for (i = 0; i < dtp->dt_maxagg; i++) {
444 		if (dtp->dt_aggdesc[i] != NULL)
445 			free(dtp->dt_aggdesc[i]);
446 	}
447 
448 	free(dtp->dt_aggdesc);
449 	dtp->dt_aggdesc = NULL;
450 	dtp->dt_maxagg = 0;
451 }
452 
453 const char *
454 dt_strdata_lookup(dtrace_hdl_t *dtp, int idx)
455 {
456 	if (idx == 0 || idx > dtp->dt_maxstrdata)
457 		return (NULL);
458 
459 	if (dtp->dt_strdata == NULL)
460 		return (NULL);
461 
462 	return (dtp->dt_strdata[idx - 1]);
463 }
464 
465 void
466 dt_strdata_destroy(dtrace_hdl_t *dtp)
467 {
468 	int i;
469 
470 	for (i = 0; i < dtp->dt_maxstrdata; i++) {
471 		free(dtp->dt_strdata[i]);
472 	}
473 
474 	free(dtp->dt_strdata);
475 	dtp->dt_strdata = NULL;
476 }
477