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