dt_map.c revision 178529
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
37static int
38dt_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
199err:
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
211int
212dt_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
231void
232dt_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
262void *
263dt_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
274void
275dt_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
288static int
289dt_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
389int
390dt_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
407void
408dt_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