xref: /illumos-gate/usr/src/lib/libdtrace/common/dt_map.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 (dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled) == -1) {
86 		rval = dt_set_errno(dtp, errno);
87 		free(enabled);
88 		return (rval);
89 	}
90 
91 	if (DTRACE_SIZEOF_EPROBEDESC(enabled) != sizeof (*enabled)) {
92 		/*
93 		 * There must be more than one action.  Allocate the
94 		 * appropriate amount of space and try again.
95 		 */
96 		if ((nenabled =
97 		    malloc(DTRACE_SIZEOF_EPROBEDESC(enabled))) != NULL)
98 			bcopy(enabled, nenabled, sizeof (*enabled));
99 
100 		free(enabled);
101 
102 		if ((enabled = nenabled) == NULL)
103 			return (dt_set_errno(dtp, EDT_NOMEM));
104 
105 		rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled);
106 
107 		if (rval == -1) {
108 			rval = dt_set_errno(dtp, errno);
109 			free(enabled);
110 			return (rval);
111 		}
112 	}
113 
114 	if ((probe = malloc(sizeof (dtrace_probedesc_t))) == NULL) {
115 		free(enabled);
116 		return (dt_set_errno(dtp, EDT_NOMEM));
117 	}
118 
119 	probe->dtpd_id = enabled->dtepd_probeid;
120 
121 	if (dt_ioctl(dtp, DTRACEIOC_PROBES, probe) == -1) {
122 		rval = dt_set_errno(dtp, errno);
123 		goto err;
124 	}
125 
126 	for (i = 0; i < enabled->dtepd_nrecs; i++) {
127 		dtrace_fmtdesc_t fmt;
128 		dtrace_recdesc_t *rec = &enabled->dtepd_rec[i];
129 
130 		if (!DTRACEACT_ISPRINTFLIKE(rec->dtrd_action))
131 			continue;
132 
133 		if (rec->dtrd_format == 0)
134 			continue;
135 
136 		if (rec->dtrd_format <= dtp->dt_maxformat &&
137 		    dtp->dt_formats[rec->dtrd_format - 1] != NULL)
138 			continue;
139 
140 		bzero(&fmt, sizeof (fmt));
141 		fmt.dtfd_format = rec->dtrd_format;
142 		fmt.dtfd_string = NULL;
143 		fmt.dtfd_length = 0;
144 
145 		if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
146 			rval = dt_set_errno(dtp, errno);
147 			goto err;
148 		}
149 
150 		if ((fmt.dtfd_string = malloc(fmt.dtfd_length)) == NULL) {
151 			rval = dt_set_errno(dtp, EDT_NOMEM);
152 			goto err;
153 		}
154 
155 		if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
156 			rval = dt_set_errno(dtp, errno);
157 			free(fmt.dtfd_string);
158 			goto err;
159 		}
160 
161 		while (rec->dtrd_format > (maxformat = dtp->dt_maxformat)) {
162 			int new_max = maxformat ? (maxformat << 1) : 1;
163 			size_t nsize = new_max * sizeof (void *);
164 			size_t osize = maxformat * sizeof (void *);
165 			void **new_formats = malloc(nsize);
166 
167 			if (new_formats == NULL) {
168 				rval = dt_set_errno(dtp, EDT_NOMEM);
169 				free(fmt.dtfd_string);
170 				goto err;
171 			}
172 
173 			bzero(new_formats, nsize);
174 			bcopy(dtp->dt_formats, new_formats, osize);
175 			free(dtp->dt_formats);
176 
177 			dtp->dt_formats = new_formats;
178 			dtp->dt_maxformat = new_max;
179 		}
180 
181 		dtp->dt_formats[rec->dtrd_format - 1] =
182 		    rec->dtrd_action == DTRACEACT_PRINTA ?
183 		    dtrace_printa_create(dtp, fmt.dtfd_string) :
184 		    dtrace_printf_create(dtp, fmt.dtfd_string);
185 
186 		free(fmt.dtfd_string);
187 
188 		if (dtp->dt_formats[rec->dtrd_format - 1] == NULL) {
189 			rval = -1; /* dt_errno is set for us */
190 			goto err;
191 		}
192 	}
193 
194 	dtp->dt_pdesc[id] = probe;
195 	dtp->dt_edesc[id] = enabled;
196 
197 	return (0);
198 
199 err:
200 	/*
201 	 * If we failed, free our allocated probes.  Note that if we failed
202 	 * while allocating formats, we aren't going to free formats that
203 	 * we have already allocated.  This is okay; these formats are
204 	 * hanging off of dt_formats and will therefore not be leaked.
205 	 */
206 	free(enabled);
207 	free(probe);
208 	return (rval);
209 }
210 
211 int
212 dt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid,
213     dtrace_eprobedesc_t **epdp, dtrace_probedesc_t **pdp)
214 {
215 	int rval;
216 
217 	if (epid >= dtp->dt_maxprobe || dtp->dt_pdesc[epid] == NULL) {
218 		if ((rval = dt_epid_add(dtp, epid)) != 0)
219 			return (rval);
220 	}
221 
222 	assert(epid < dtp->dt_maxprobe);
223 	assert(dtp->dt_edesc[epid] != NULL);
224 	assert(dtp->dt_pdesc[epid] != NULL);
225 	*epdp = dtp->dt_edesc[epid];
226 	*pdp = dtp->dt_pdesc[epid];
227 
228 	return (0);
229 }
230 
231 void
232 dt_epid_destroy(dtrace_hdl_t *dtp)
233 {
234 	size_t i;
235 
236 	assert((dtp->dt_pdesc != NULL && dtp->dt_edesc != NULL &&
237 	    dtp->dt_maxprobe > 0) || (dtp->dt_pdesc == NULL &&
238 	    dtp->dt_edesc == NULL && dtp->dt_maxprobe == 0));
239 
240 	if (dtp->dt_pdesc == NULL)
241 		return;
242 
243 	for (i = 0; i < dtp->dt_maxprobe; i++) {
244 		if (dtp->dt_edesc[i] == NULL) {
245 			assert(dtp->dt_pdesc[i] == NULL);
246 			continue;
247 		}
248 
249 		assert(dtp->dt_pdesc[i] != NULL);
250 		free(dtp->dt_edesc[i]);
251 		free(dtp->dt_pdesc[i]);
252 	}
253 
254 	free(dtp->dt_pdesc);
255 	dtp->dt_pdesc = NULL;
256 
257 	free(dtp->dt_edesc);
258 	dtp->dt_edesc = NULL;
259 	dtp->dt_maxprobe = 0;
260 }
261 
262 void *
263 dt_format_lookup(dtrace_hdl_t *dtp, int format)
264 {
265 	if (format == 0 || format > dtp->dt_maxformat)
266 		return (NULL);
267 
268 	if (dtp->dt_formats == NULL)
269 		return (NULL);
270 
271 	return (dtp->dt_formats[format - 1]);
272 }
273 
274 void
275 dt_format_destroy(dtrace_hdl_t *dtp)
276 {
277 	int i;
278 
279 	for (i = 0; i < dtp->dt_maxformat; i++) {
280 		if (dtp->dt_formats[i] != NULL)
281 			dt_printf_destroy(dtp->dt_formats[i]);
282 	}
283 
284 	free(dtp->dt_formats);
285 	dtp->dt_formats = NULL;
286 }
287 
288 static int
289 dt_aggid_add(dtrace_hdl_t *dtp, dtrace_aggid_t id)
290 {
291 	dtrace_id_t max;
292 	dtrace_epid_t epid;
293 	int rval;
294 
295 	while (id >= (max = dtp->dt_maxagg) || dtp->dt_aggdesc == NULL) {
296 		dtrace_id_t new_max = max ? (max << 1) : 1;
297 		size_t nsize = new_max * sizeof (void *);
298 		dtrace_aggdesc_t **new_aggdesc;
299 
300 		if ((new_aggdesc = malloc(nsize)) == NULL)
301 			return (dt_set_errno(dtp, EDT_NOMEM));
302 
303 		bzero(new_aggdesc, nsize);
304 
305 		if (dtp->dt_aggdesc != NULL) {
306 			bcopy(dtp->dt_aggdesc, new_aggdesc,
307 			    max * sizeof (void *));
308 			free(dtp->dt_aggdesc);
309 		}
310 
311 		dtp->dt_aggdesc = new_aggdesc;
312 		dtp->dt_maxagg = new_max;
313 	}
314 
315 	if (dtp->dt_aggdesc[id] == NULL) {
316 		dtrace_aggdesc_t *agg, *nagg;
317 
318 		if ((agg = malloc(sizeof (dtrace_aggdesc_t))) == NULL)
319 			return (dt_set_errno(dtp, EDT_NOMEM));
320 
321 		bzero(agg, sizeof (dtrace_aggdesc_t));
322 		agg->dtagd_id = id;
323 		agg->dtagd_nrecs = 1;
324 
325 		if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg) == -1) {
326 			rval = dt_set_errno(dtp, errno);
327 			free(agg);
328 			return (rval);
329 		}
330 
331 		if (DTRACE_SIZEOF_AGGDESC(agg) != sizeof (*agg)) {
332 			/*
333 			 * There must be more than one action.  Allocate the
334 			 * appropriate amount of space and try again.
335 			 */
336 			if ((nagg = malloc(DTRACE_SIZEOF_AGGDESC(agg))) != NULL)
337 				bcopy(agg, nagg, sizeof (*agg));
338 
339 			free(agg);
340 
341 			if ((agg = nagg) == NULL)
342 				return (dt_set_errno(dtp, EDT_NOMEM));
343 
344 			rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg);
345 
346 			if (rval == -1) {
347 				rval = dt_set_errno(dtp, errno);
348 				free(agg);
349 				return (rval);
350 			}
351 		}
352 
353 		/*
354 		 * If we have a uarg, it's a pointer to the compiler-generated
355 		 * statement; we'll use this value to get the name and
356 		 * compiler-generated variable ID for the aggregation.  If
357 		 * we're grabbing an anonymous enabling, this pointer value
358 		 * is obviously meaningless -- and in this case, we can't
359 		 * provide the compiler-generated aggregation information.
360 		 */
361 		if (dtp->dt_options[DTRACEOPT_GRABANON] == DTRACEOPT_UNSET &&
362 		    agg->dtagd_rec[0].dtrd_uarg != NULL) {
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