dt_map.c revision 178562
1178479Sjb/*
2178479Sjb * CDDL HEADER START
3178479Sjb *
4178479Sjb * The contents of this file are subject to the terms of the
5178479Sjb * Common Development and Distribution License (the "License").
6178479Sjb * You may not use this file except in compliance with the License.
7178479Sjb *
8178479Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9178479Sjb * or http://www.opensolaris.org/os/licensing.
10178479Sjb * See the License for the specific language governing permissions
11178479Sjb * and limitations under the License.
12178479Sjb *
13178479Sjb * When distributing Covered Code, include this CDDL HEADER in each
14178479Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15178479Sjb * If applicable, add the following below this CDDL HEADER, with the
16178479Sjb * fields enclosed by brackets "[]" replaced with your own identifying
17178479Sjb * information: Portions Copyright [yyyy] [name of copyright owner]
18178479Sjb *
19178479Sjb * CDDL HEADER END
20178479Sjb */
21178479Sjb/*
22178479Sjb * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23178479Sjb * Use is subject to license terms.
24178479Sjb */
25178479Sjb
26178479Sjb#pragma ident	"%Z%%M%	%I%	%E% SMI"
27178479Sjb
28178479Sjb#include <stdlib.h>
29178479Sjb#include <strings.h>
30178479Sjb#include <errno.h>
31178479Sjb#include <unistd.h>
32178479Sjb#include <assert.h>
33178479Sjb
34178479Sjb#include <dt_impl.h>
35178479Sjb#include <dt_printf.h>
36178479Sjb
37178479Sjbstatic int
38178479Sjbdt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id)
39178479Sjb{
40178479Sjb	dtrace_id_t max;
41178479Sjb	int rval, i, maxformat;
42178479Sjb	dtrace_eprobedesc_t *enabled, *nenabled;
43178479Sjb	dtrace_probedesc_t *probe;
44178479Sjb
45178479Sjb	while (id >= (max = dtp->dt_maxprobe) || dtp->dt_pdesc == NULL) {
46178479Sjb		dtrace_id_t new_max = max ? (max << 1) : 1;
47178479Sjb		size_t nsize = new_max * sizeof (void *);
48178479Sjb		dtrace_probedesc_t **new_pdesc;
49178479Sjb		dtrace_eprobedesc_t **new_edesc;
50178479Sjb
51178479Sjb		if ((new_pdesc = malloc(nsize)) == NULL ||
52178479Sjb		    (new_edesc = malloc(nsize)) == NULL) {
53178479Sjb			free(new_pdesc);
54178479Sjb			return (dt_set_errno(dtp, EDT_NOMEM));
55178479Sjb		}
56178479Sjb
57178479Sjb		bzero(new_pdesc, nsize);
58178479Sjb		bzero(new_edesc, nsize);
59178479Sjb
60178479Sjb		if (dtp->dt_pdesc != NULL) {
61178479Sjb			size_t osize = max * sizeof (void *);
62178479Sjb
63178479Sjb			bcopy(dtp->dt_pdesc, new_pdesc, osize);
64178479Sjb			free(dtp->dt_pdesc);
65178479Sjb
66178479Sjb			bcopy(dtp->dt_edesc, new_edesc, osize);
67178479Sjb			free(dtp->dt_edesc);
68178479Sjb		}
69178479Sjb
70178479Sjb		dtp->dt_pdesc = new_pdesc;
71178479Sjb		dtp->dt_edesc = new_edesc;
72178479Sjb		dtp->dt_maxprobe = new_max;
73178479Sjb	}
74178479Sjb
75178479Sjb	if (dtp->dt_pdesc[id] != NULL)
76178479Sjb		return (0);
77178479Sjb
78178479Sjb	if ((enabled = malloc(sizeof (dtrace_eprobedesc_t))) == NULL)
79178479Sjb		return (dt_set_errno(dtp, EDT_NOMEM));
80178479Sjb
81178479Sjb	bzero(enabled, sizeof (dtrace_eprobedesc_t));
82178479Sjb	enabled->dtepd_epid = id;
83178479Sjb	enabled->dtepd_nrecs = 1;
84178479Sjb
85178562Sjb#if defined(sun)
86178479Sjb	if (dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled) == -1) {
87178562Sjb#else
88178562Sjb	if (dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled) == -1) {
89178562Sjb#endif
90178479Sjb		rval = dt_set_errno(dtp, errno);
91178479Sjb		free(enabled);
92178479Sjb		return (rval);
93178479Sjb	}
94178479Sjb
95178479Sjb	if (DTRACE_SIZEOF_EPROBEDESC(enabled) != sizeof (*enabled)) {
96178479Sjb		/*
97178479Sjb		 * There must be more than one action.  Allocate the
98178479Sjb		 * appropriate amount of space and try again.
99178479Sjb		 */
100178479Sjb		if ((nenabled =
101178479Sjb		    malloc(DTRACE_SIZEOF_EPROBEDESC(enabled))) != NULL)
102178479Sjb			bcopy(enabled, nenabled, sizeof (*enabled));
103178479Sjb
104178479Sjb		free(enabled);
105178479Sjb
106178479Sjb		if ((enabled = nenabled) == NULL)
107178479Sjb			return (dt_set_errno(dtp, EDT_NOMEM));
108178479Sjb
109178562Sjb#if defined(sun)
110178479Sjb		rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled);
111178562Sjb#else
112178562Sjb		rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled);
113178562Sjb#endif
114178479Sjb
115178479Sjb		if (rval == -1) {
116178479Sjb			rval = dt_set_errno(dtp, errno);
117178479Sjb			free(enabled);
118178479Sjb			return (rval);
119178479Sjb		}
120178479Sjb	}
121178479Sjb
122178479Sjb	if ((probe = malloc(sizeof (dtrace_probedesc_t))) == NULL) {
123178479Sjb		free(enabled);
124178479Sjb		return (dt_set_errno(dtp, EDT_NOMEM));
125178479Sjb	}
126178479Sjb
127178479Sjb	probe->dtpd_id = enabled->dtepd_probeid;
128178479Sjb
129178479Sjb	if (dt_ioctl(dtp, DTRACEIOC_PROBES, probe) == -1) {
130178479Sjb		rval = dt_set_errno(dtp, errno);
131178479Sjb		goto err;
132178479Sjb	}
133178479Sjb
134178479Sjb	for (i = 0; i < enabled->dtepd_nrecs; i++) {
135178479Sjb		dtrace_fmtdesc_t fmt;
136178479Sjb		dtrace_recdesc_t *rec = &enabled->dtepd_rec[i];
137178479Sjb
138178479Sjb		if (!DTRACEACT_ISPRINTFLIKE(rec->dtrd_action))
139178479Sjb			continue;
140178479Sjb
141178479Sjb		if (rec->dtrd_format == 0)
142178479Sjb			continue;
143178479Sjb
144178479Sjb		if (rec->dtrd_format <= dtp->dt_maxformat &&
145178479Sjb		    dtp->dt_formats[rec->dtrd_format - 1] != NULL)
146178479Sjb			continue;
147178479Sjb
148178479Sjb		bzero(&fmt, sizeof (fmt));
149178479Sjb		fmt.dtfd_format = rec->dtrd_format;
150178479Sjb		fmt.dtfd_string = NULL;
151178479Sjb		fmt.dtfd_length = 0;
152178479Sjb
153178479Sjb		if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
154178479Sjb			rval = dt_set_errno(dtp, errno);
155178479Sjb			goto err;
156178479Sjb		}
157178479Sjb
158178479Sjb		if ((fmt.dtfd_string = malloc(fmt.dtfd_length)) == NULL) {
159178479Sjb			rval = dt_set_errno(dtp, EDT_NOMEM);
160178479Sjb			goto err;
161178479Sjb		}
162178479Sjb
163178479Sjb		if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
164178479Sjb			rval = dt_set_errno(dtp, errno);
165178479Sjb			free(fmt.dtfd_string);
166178479Sjb			goto err;
167178479Sjb		}
168178479Sjb
169178479Sjb		while (rec->dtrd_format > (maxformat = dtp->dt_maxformat)) {
170178479Sjb			int new_max = maxformat ? (maxformat << 1) : 1;
171178479Sjb			size_t nsize = new_max * sizeof (void *);
172178479Sjb			size_t osize = maxformat * sizeof (void *);
173178479Sjb			void **new_formats = malloc(nsize);
174178479Sjb
175178479Sjb			if (new_formats == NULL) {
176178479Sjb				rval = dt_set_errno(dtp, EDT_NOMEM);
177178479Sjb				free(fmt.dtfd_string);
178178479Sjb				goto err;
179178479Sjb			}
180178479Sjb
181178479Sjb			bzero(new_formats, nsize);
182178479Sjb			bcopy(dtp->dt_formats, new_formats, osize);
183178479Sjb			free(dtp->dt_formats);
184178479Sjb
185178479Sjb			dtp->dt_formats = new_formats;
186178479Sjb			dtp->dt_maxformat = new_max;
187178479Sjb		}
188178479Sjb
189178479Sjb		dtp->dt_formats[rec->dtrd_format - 1] =
190178479Sjb		    rec->dtrd_action == DTRACEACT_PRINTA ?
191178479Sjb		    dtrace_printa_create(dtp, fmt.dtfd_string) :
192178479Sjb		    dtrace_printf_create(dtp, fmt.dtfd_string);
193178479Sjb
194178479Sjb		free(fmt.dtfd_string);
195178479Sjb
196178479Sjb		if (dtp->dt_formats[rec->dtrd_format - 1] == NULL) {
197178479Sjb			rval = -1; /* dt_errno is set for us */
198178479Sjb			goto err;
199178479Sjb		}
200178479Sjb	}
201178479Sjb
202178479Sjb	dtp->dt_pdesc[id] = probe;
203178479Sjb	dtp->dt_edesc[id] = enabled;
204178479Sjb
205178479Sjb	return (0);
206178479Sjb
207178479Sjberr:
208178479Sjb	/*
209178479Sjb	 * If we failed, free our allocated probes.  Note that if we failed
210178479Sjb	 * while allocating formats, we aren't going to free formats that
211178479Sjb	 * we have already allocated.  This is okay; these formats are
212178479Sjb	 * hanging off of dt_formats and will therefore not be leaked.
213178479Sjb	 */
214178479Sjb	free(enabled);
215178479Sjb	free(probe);
216178479Sjb	return (rval);
217178479Sjb}
218178479Sjb
219178479Sjbint
220178479Sjbdt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid,
221178479Sjb    dtrace_eprobedesc_t **epdp, dtrace_probedesc_t **pdp)
222178479Sjb{
223178479Sjb	int rval;
224178479Sjb
225178479Sjb	if (epid >= dtp->dt_maxprobe || dtp->dt_pdesc[epid] == NULL) {
226178479Sjb		if ((rval = dt_epid_add(dtp, epid)) != 0)
227178479Sjb			return (rval);
228178479Sjb	}
229178479Sjb
230178479Sjb	assert(epid < dtp->dt_maxprobe);
231178479Sjb	assert(dtp->dt_edesc[epid] != NULL);
232178479Sjb	assert(dtp->dt_pdesc[epid] != NULL);
233178479Sjb	*epdp = dtp->dt_edesc[epid];
234178479Sjb	*pdp = dtp->dt_pdesc[epid];
235178479Sjb
236178479Sjb	return (0);
237178479Sjb}
238178479Sjb
239178479Sjbvoid
240178479Sjbdt_epid_destroy(dtrace_hdl_t *dtp)
241178479Sjb{
242178479Sjb	size_t i;
243178479Sjb
244178479Sjb	assert((dtp->dt_pdesc != NULL && dtp->dt_edesc != NULL &&
245178479Sjb	    dtp->dt_maxprobe > 0) || (dtp->dt_pdesc == NULL &&
246178479Sjb	    dtp->dt_edesc == NULL && dtp->dt_maxprobe == 0));
247178479Sjb
248178479Sjb	if (dtp->dt_pdesc == NULL)
249178479Sjb		return;
250178479Sjb
251178479Sjb	for (i = 0; i < dtp->dt_maxprobe; i++) {
252178479Sjb		if (dtp->dt_edesc[i] == NULL) {
253178479Sjb			assert(dtp->dt_pdesc[i] == NULL);
254178479Sjb			continue;
255178479Sjb		}
256178479Sjb
257178479Sjb		assert(dtp->dt_pdesc[i] != NULL);
258178479Sjb		free(dtp->dt_edesc[i]);
259178479Sjb		free(dtp->dt_pdesc[i]);
260178479Sjb	}
261178479Sjb
262178479Sjb	free(dtp->dt_pdesc);
263178479Sjb	dtp->dt_pdesc = NULL;
264178479Sjb
265178479Sjb	free(dtp->dt_edesc);
266178479Sjb	dtp->dt_edesc = NULL;
267178479Sjb	dtp->dt_maxprobe = 0;
268178479Sjb}
269178479Sjb
270178479Sjbvoid *
271178479Sjbdt_format_lookup(dtrace_hdl_t *dtp, int format)
272178479Sjb{
273178479Sjb	if (format == 0 || format > dtp->dt_maxformat)
274178479Sjb		return (NULL);
275178479Sjb
276178479Sjb	if (dtp->dt_formats == NULL)
277178479Sjb		return (NULL);
278178479Sjb
279178479Sjb	return (dtp->dt_formats[format - 1]);
280178479Sjb}
281178479Sjb
282178479Sjbvoid
283178479Sjbdt_format_destroy(dtrace_hdl_t *dtp)
284178479Sjb{
285178479Sjb	int i;
286178479Sjb
287178479Sjb	for (i = 0; i < dtp->dt_maxformat; i++) {
288178479Sjb		if (dtp->dt_formats[i] != NULL)
289178479Sjb			dt_printf_destroy(dtp->dt_formats[i]);
290178479Sjb	}
291178479Sjb
292178479Sjb	free(dtp->dt_formats);
293178479Sjb	dtp->dt_formats = NULL;
294178479Sjb}
295178479Sjb
296178479Sjbstatic int
297178479Sjbdt_aggid_add(dtrace_hdl_t *dtp, dtrace_aggid_t id)
298178479Sjb{
299178479Sjb	dtrace_id_t max;
300178479Sjb	dtrace_epid_t epid;
301178479Sjb	int rval;
302178479Sjb
303178479Sjb	while (id >= (max = dtp->dt_maxagg) || dtp->dt_aggdesc == NULL) {
304178479Sjb		dtrace_id_t new_max = max ? (max << 1) : 1;
305178479Sjb		size_t nsize = new_max * sizeof (void *);
306178479Sjb		dtrace_aggdesc_t **new_aggdesc;
307178479Sjb
308178479Sjb		if ((new_aggdesc = malloc(nsize)) == NULL)
309178479Sjb			return (dt_set_errno(dtp, EDT_NOMEM));
310178479Sjb
311178479Sjb		bzero(new_aggdesc, nsize);
312178479Sjb
313178479Sjb		if (dtp->dt_aggdesc != NULL) {
314178479Sjb			bcopy(dtp->dt_aggdesc, new_aggdesc,
315178479Sjb			    max * sizeof (void *));
316178479Sjb			free(dtp->dt_aggdesc);
317178479Sjb		}
318178479Sjb
319178479Sjb		dtp->dt_aggdesc = new_aggdesc;
320178479Sjb		dtp->dt_maxagg = new_max;
321178479Sjb	}
322178479Sjb
323178479Sjb	if (dtp->dt_aggdesc[id] == NULL) {
324178479Sjb		dtrace_aggdesc_t *agg, *nagg;
325178479Sjb
326178479Sjb		if ((agg = malloc(sizeof (dtrace_aggdesc_t))) == NULL)
327178479Sjb			return (dt_set_errno(dtp, EDT_NOMEM));
328178479Sjb
329178479Sjb		bzero(agg, sizeof (dtrace_aggdesc_t));
330178479Sjb		agg->dtagd_id = id;
331178479Sjb		agg->dtagd_nrecs = 1;
332178479Sjb
333178562Sjb#if defined(sun)
334178479Sjb		if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg) == -1) {
335178562Sjb#else
336178562Sjb		if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg) == -1) {
337178562Sjb#endif
338178479Sjb			rval = dt_set_errno(dtp, errno);
339178479Sjb			free(agg);
340178479Sjb			return (rval);
341178479Sjb		}
342178479Sjb
343178479Sjb		if (DTRACE_SIZEOF_AGGDESC(agg) != sizeof (*agg)) {
344178479Sjb			/*
345178479Sjb			 * There must be more than one action.  Allocate the
346178479Sjb			 * appropriate amount of space and try again.
347178479Sjb			 */
348178479Sjb			if ((nagg = malloc(DTRACE_SIZEOF_AGGDESC(agg))) != NULL)
349178479Sjb				bcopy(agg, nagg, sizeof (*agg));
350178479Sjb
351178479Sjb			free(agg);
352178479Sjb
353178479Sjb			if ((agg = nagg) == NULL)
354178479Sjb				return (dt_set_errno(dtp, EDT_NOMEM));
355178479Sjb
356178562Sjb#if defined(sun)
357178479Sjb			rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg);
358178562Sjb#else
359178562Sjb			rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg);
360178562Sjb#endif
361178479Sjb
362178479Sjb			if (rval == -1) {
363178479Sjb				rval = dt_set_errno(dtp, errno);
364178479Sjb				free(agg);
365178479Sjb				return (rval);
366178479Sjb			}
367178479Sjb		}
368178479Sjb
369178479Sjb		/*
370178479Sjb		 * If we have a uarg, it's a pointer to the compiler-generated
371178479Sjb		 * statement; we'll use this value to get the name and
372178479Sjb		 * compiler-generated variable ID for the aggregation.  If
373178479Sjb		 * we're grabbing an anonymous enabling, this pointer value
374178479Sjb		 * is obviously meaningless -- and in this case, we can't
375178479Sjb		 * provide the compiler-generated aggregation information.
376178479Sjb		 */
377178479Sjb		if (dtp->dt_options[DTRACEOPT_GRABANON] == DTRACEOPT_UNSET &&
378178562Sjb		    agg->dtagd_rec[0].dtrd_uarg != 0) {
379178479Sjb			dtrace_stmtdesc_t *sdp;
380178479Sjb			dt_ident_t *aid;
381178479Sjb
382178479Sjb			sdp = (dtrace_stmtdesc_t *)(uintptr_t)
383178479Sjb			    agg->dtagd_rec[0].dtrd_uarg;
384178479Sjb			aid = sdp->dtsd_aggdata;
385178479Sjb			agg->dtagd_name = aid->di_name;
386178479Sjb			agg->dtagd_varid = aid->di_id;
387178479Sjb		} else {
388178479Sjb			agg->dtagd_varid = DTRACE_AGGVARIDNONE;
389178479Sjb		}
390178479Sjb
391178479Sjb		if ((epid = agg->dtagd_epid) >= dtp->dt_maxprobe ||
392178479Sjb		    dtp->dt_pdesc[epid] == NULL) {
393178479Sjb			if ((rval = dt_epid_add(dtp, epid)) != 0) {
394178479Sjb				free(agg);
395178479Sjb				return (rval);
396178479Sjb			}
397178479Sjb		}
398178479Sjb
399178479Sjb		dtp->dt_aggdesc[id] = agg;
400178479Sjb	}
401178479Sjb
402178479Sjb	return (0);
403178479Sjb}
404178479Sjb
405178479Sjbint
406178479Sjbdt_aggid_lookup(dtrace_hdl_t *dtp, dtrace_aggid_t aggid,
407178479Sjb    dtrace_aggdesc_t **adp)
408178479Sjb{
409178479Sjb	int rval;
410178479Sjb
411178479Sjb	if (aggid >= dtp->dt_maxagg || dtp->dt_aggdesc[aggid] == NULL) {
412178479Sjb		if ((rval = dt_aggid_add(dtp, aggid)) != 0)
413178479Sjb			return (rval);
414178479Sjb	}
415178479Sjb
416178479Sjb	assert(aggid < dtp->dt_maxagg);
417178479Sjb	assert(dtp->dt_aggdesc[aggid] != NULL);
418178479Sjb	*adp = dtp->dt_aggdesc[aggid];
419178479Sjb
420178479Sjb	return (0);
421178479Sjb}
422178479Sjb
423178479Sjbvoid
424178479Sjbdt_aggid_destroy(dtrace_hdl_t *dtp)
425178479Sjb{
426178479Sjb	size_t i;
427178479Sjb
428178479Sjb	assert((dtp->dt_aggdesc != NULL && dtp->dt_maxagg != 0) ||
429178479Sjb	    (dtp->dt_aggdesc == NULL && dtp->dt_maxagg == 0));
430178479Sjb
431178479Sjb	if (dtp->dt_aggdesc == NULL)
432178479Sjb		return;
433178479Sjb
434178479Sjb	for (i = 0; i < dtp->dt_maxagg; i++) {
435178479Sjb		if (dtp->dt_aggdesc[i] != NULL)
436178479Sjb			free(dtp->dt_aggdesc[i]);
437178479Sjb	}
438178479Sjb
439178479Sjb	free(dtp->dt_aggdesc);
440178479Sjb	dtp->dt_aggdesc = NULL;
441178479Sjb	dtp->dt_maxagg = 0;
442178479Sjb}
443