dt_map.c revision 178562
1178173Simp/*
2178173Simp * CDDL HEADER START
3178173Simp *
4178173Simp * The contents of this file are subject to the terms of the
5178173Simp * Common Development and Distribution License (the "License").
6178173Simp * You may not use this file except in compliance with the License.
7178173Simp *
8178173Simp * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9178173Simp * or http://www.opensolaris.org/os/licensing.
10178173Simp * See the License for the specific language governing permissions
11178173Simp * and limitations under the License.
12178173Simp *
13178173Simp * When distributing Covered Code, include this CDDL HEADER in each
14178173Simp * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15178173Simp * If applicable, add the following below this CDDL HEADER, with the
16178173Simp * fields enclosed by brackets "[]" replaced with your own identifying
17178173Simp * information: Portions Copyright [yyyy] [name of copyright owner]
18178173Simp *
19178173Simp * CDDL HEADER END
20178173Simp */
21178173Simp/*
22178173Simp * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23178173Simp * Use is subject to license terms.
24178173Simp */
25178173Simp
26178173Simp#pragma ident	"%Z%%M%	%I%	%E% SMI"
27178173Simp
28178173Simp#include <stdlib.h>
29178173Simp#include <strings.h>
30178173Simp#include <errno.h>
31178173Simp#include <unistd.h>
32178173Simp#include <assert.h>
33178173Simp
34178173Simp#include <dt_impl.h>
35178173Simp#include <dt_printf.h>
36178173Simp
37178173Simpstatic int
38178173Simpdt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id)
39178173Simp{
40178173Simp	dtrace_id_t max;
41178173Simp	int rval, i, maxformat;
42178173Simp	dtrace_eprobedesc_t *enabled, *nenabled;
43178173Simp	dtrace_probedesc_t *probe;
44178173Simp
45178173Simp	while (id >= (max = dtp->dt_maxprobe) || dtp->dt_pdesc == NULL) {
46178173Simp		dtrace_id_t new_max = max ? (max << 1) : 1;
47182901Sgonzo		size_t nsize = new_max * sizeof (void *);
48182901Sgonzo		dtrace_probedesc_t **new_pdesc;
49178173Simp		dtrace_eprobedesc_t **new_edesc;
50178173Simp
51178173Simp		if ((new_pdesc = malloc(nsize)) == NULL ||
52178173Simp		    (new_edesc = malloc(nsize)) == NULL) {
53178173Simp			free(new_pdesc);
54178173Simp			return (dt_set_errno(dtp, EDT_NOMEM));
55178173Simp		}
56178173Simp
57178173Simp		bzero(new_pdesc, nsize);
58178173Simp		bzero(new_edesc, nsize);
59178173Simp
60178173Simp		if (dtp->dt_pdesc != NULL) {
61178173Simp			size_t osize = max * sizeof (void *);
62178173Simp
63178173Simp			bcopy(dtp->dt_pdesc, new_pdesc, osize);
64178173Simp			free(dtp->dt_pdesc);
65178173Simp
66178173Simp			bcopy(dtp->dt_edesc, new_edesc, osize);
67178173Simp			free(dtp->dt_edesc);
68178173Simp		}
69178173Simp
70178173Simp		dtp->dt_pdesc = new_pdesc;
71178173Simp		dtp->dt_edesc = new_edesc;
72178173Simp		dtp->dt_maxprobe = new_max;
73178173Simp	}
74178173Simp
75178173Simp	if (dtp->dt_pdesc[id] != NULL)
76178173Simp		return (0);
77178173Simp
78178173Simp	if ((enabled = malloc(sizeof (dtrace_eprobedesc_t))) == NULL)
79178173Simp		return (dt_set_errno(dtp, EDT_NOMEM));
80178173Simp
81178173Simp	bzero(enabled, sizeof (dtrace_eprobedesc_t));
82178173Simp	enabled->dtepd_epid = id;
83178173Simp	enabled->dtepd_nrecs = 1;
84178173Simp
85178173Simp#if defined(sun)
86178173Simp	if (dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled) == -1) {
87178173Simp#else
88178173Simp	if (dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled) == -1) {
89178173Simp#endif
90178173Simp		rval = dt_set_errno(dtp, errno);
91178173Simp		free(enabled);
92178173Simp		return (rval);
93178173Simp	}
94178173Simp
95178173Simp	if (DTRACE_SIZEOF_EPROBEDESC(enabled) != sizeof (*enabled)) {
96178173Simp		/*
97178173Simp		 * There must be more than one action.  Allocate the
98178173Simp		 * appropriate amount of space and try again.
99178173Simp		 */
100178173Simp		if ((nenabled =
101178173Simp		    malloc(DTRACE_SIZEOF_EPROBEDESC(enabled))) != NULL)
102178173Simp			bcopy(enabled, nenabled, sizeof (*enabled));
103178173Simp
104178173Simp		free(enabled);
105178173Simp
106178173Simp		if ((enabled = nenabled) == NULL)
107178173Simp			return (dt_set_errno(dtp, EDT_NOMEM));
108178173Simp
109178173Simp#if defined(sun)
110178173Simp		rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled);
111178173Simp#else
112178173Simp		rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled);
113178173Simp#endif
114178173Simp
115178173Simp		if (rval == -1) {
116178173Simp			rval = dt_set_errno(dtp, errno);
117178173Simp			free(enabled);
118178173Simp			return (rval);
119178173Simp		}
120178173Simp	}
121178173Simp
122178173Simp	if ((probe = malloc(sizeof (dtrace_probedesc_t))) == NULL) {
123178173Simp		free(enabled);
124178173Simp		return (dt_set_errno(dtp, EDT_NOMEM));
125178173Simp	}
126178173Simp
127178173Simp	probe->dtpd_id = enabled->dtepd_probeid;
128178173Simp
129178173Simp	if (dt_ioctl(dtp, DTRACEIOC_PROBES, probe) == -1) {
130178173Simp		rval = dt_set_errno(dtp, errno);
131178173Simp		goto err;
132178173Simp	}
133178173Simp
134178173Simp	for (i = 0; i < enabled->dtepd_nrecs; i++) {
135178173Simp		dtrace_fmtdesc_t fmt;
136178173Simp		dtrace_recdesc_t *rec = &enabled->dtepd_rec[i];
137178173Simp
138178173Simp		if (!DTRACEACT_ISPRINTFLIKE(rec->dtrd_action))
139178173Simp			continue;
140178173Simp
141178173Simp		if (rec->dtrd_format == 0)
142178173Simp			continue;
143178173Simp
144178173Simp		if (rec->dtrd_format <= dtp->dt_maxformat &&
145178173Simp		    dtp->dt_formats[rec->dtrd_format - 1] != NULL)
146178173Simp			continue;
147178173Simp
148178173Simp		bzero(&fmt, sizeof (fmt));
149178173Simp		fmt.dtfd_format = rec->dtrd_format;
150178173Simp		fmt.dtfd_string = NULL;
151178173Simp		fmt.dtfd_length = 0;
152178173Simp
153178173Simp		if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
154178173Simp			rval = dt_set_errno(dtp, errno);
155178173Simp			goto err;
156178173Simp		}
157178173Simp
158178173Simp		if ((fmt.dtfd_string = malloc(fmt.dtfd_length)) == NULL) {
159178173Simp			rval = dt_set_errno(dtp, EDT_NOMEM);
160178173Simp			goto err;
161178173Simp		}
162178173Simp
163178173Simp		if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
164178173Simp			rval = dt_set_errno(dtp, errno);
165178173Simp			free(fmt.dtfd_string);
166178173Simp			goto err;
167178173Simp		}
168178173Simp
169178173Simp		while (rec->dtrd_format > (maxformat = dtp->dt_maxformat)) {
170178173Simp			int new_max = maxformat ? (maxformat << 1) : 1;
171178173Simp			size_t nsize = new_max * sizeof (void *);
172178173Simp			size_t osize = maxformat * sizeof (void *);
173178173Simp			void **new_formats = malloc(nsize);
174178173Simp
175178173Simp			if (new_formats == NULL) {
176178173Simp				rval = dt_set_errno(dtp, EDT_NOMEM);
177178173Simp				free(fmt.dtfd_string);
178178173Simp				goto err;
179178173Simp			}
180178173Simp
181178173Simp			bzero(new_formats, nsize);
182178173Simp			bcopy(dtp->dt_formats, new_formats, osize);
183178173Simp			free(dtp->dt_formats);
184178173Simp
185178173Simp			dtp->dt_formats = new_formats;
186178173Simp			dtp->dt_maxformat = new_max;
187178173Simp		}
188178173Simp
189178173Simp		dtp->dt_formats[rec->dtrd_format - 1] =
190178173Simp		    rec->dtrd_action == DTRACEACT_PRINTA ?
191178173Simp		    dtrace_printa_create(dtp, fmt.dtfd_string) :
192178173Simp		    dtrace_printf_create(dtp, fmt.dtfd_string);
193178173Simp
194178173Simp		free(fmt.dtfd_string);
195178173Simp
196178173Simp		if (dtp->dt_formats[rec->dtrd_format - 1] == NULL) {
197178173Simp			rval = -1; /* dt_errno is set for us */
198178173Simp			goto err;
199178173Simp		}
200178173Simp	}
201178173Simp
202178173Simp	dtp->dt_pdesc[id] = probe;
203178173Simp	dtp->dt_edesc[id] = enabled;
204178173Simp
205178173Simp	return (0);
206178173Simp
207178173Simperr:
208178173Simp	/*
209178173Simp	 * If we failed, free our allocated probes.  Note that if we failed
210178173Simp	 * while allocating formats, we aren't going to free formats that
211178173Simp	 * we have already allocated.  This is okay; these formats are
212178173Simp	 * hanging off of dt_formats and will therefore not be leaked.
213178173Simp	 */
214178173Simp	free(enabled);
215178173Simp	free(probe);
216178173Simp	return (rval);
217178173Simp}
218178173Simp
219178173Simpint
220178173Simpdt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid,
221178173Simp    dtrace_eprobedesc_t **epdp, dtrace_probedesc_t **pdp)
222178173Simp{
223178173Simp	int rval;
224178173Simp
225178173Simp	if (epid >= dtp->dt_maxprobe || dtp->dt_pdesc[epid] == NULL) {
226178173Simp		if ((rval = dt_epid_add(dtp, epid)) != 0)
227178173Simp			return (rval);
228178173Simp	}
229178173Simp
230178173Simp	assert(epid < dtp->dt_maxprobe);
231178173Simp	assert(dtp->dt_edesc[epid] != NULL);
232178173Simp	assert(dtp->dt_pdesc[epid] != NULL);
233178173Simp	*epdp = dtp->dt_edesc[epid];
234178173Simp	*pdp = dtp->dt_pdesc[epid];
235178173Simp
236178173Simp	return (0);
237178173Simp}
238178173Simp
239178173Simpvoid
240178173Simpdt_epid_destroy(dtrace_hdl_t *dtp)
241178173Simp{
242178173Simp	size_t i;
243178173Simp
244178173Simp	assert((dtp->dt_pdesc != NULL && dtp->dt_edesc != NULL &&
245178173Simp	    dtp->dt_maxprobe > 0) || (dtp->dt_pdesc == NULL &&
246178173Simp	    dtp->dt_edesc == NULL && dtp->dt_maxprobe == 0));
247178173Simp
248178173Simp	if (dtp->dt_pdesc == NULL)
249178173Simp		return;
250178173Simp
251178173Simp	for (i = 0; i < dtp->dt_maxprobe; i++) {
252178173Simp		if (dtp->dt_edesc[i] == NULL) {
253178173Simp			assert(dtp->dt_pdesc[i] == NULL);
254178173Simp			continue;
255178173Simp		}
256178173Simp
257178173Simp		assert(dtp->dt_pdesc[i] != NULL);
258178173Simp		free(dtp->dt_edesc[i]);
259178173Simp		free(dtp->dt_pdesc[i]);
260178173Simp	}
261178173Simp
262178173Simp	free(dtp->dt_pdesc);
263178173Simp	dtp->dt_pdesc = NULL;
264178173Simp
265178173Simp	free(dtp->dt_edesc);
266178173Simp	dtp->dt_edesc = NULL;
267178173Simp	dtp->dt_maxprobe = 0;
268178173Simp}
269178173Simp
270178173Simpvoid *
271178173Simpdt_format_lookup(dtrace_hdl_t *dtp, int format)
272178173Simp{
273178173Simp	if (format == 0 || format > dtp->dt_maxformat)
274178173Simp		return (NULL);
275178173Simp
276183173Simp	if (dtp->dt_formats == NULL)
277178173Simp		return (NULL);
278178173Simp
279178173Simp	return (dtp->dt_formats[format - 1]);
280178173Simp}
281178173Simp
282178173Simpvoid
283178173Simpdt_format_destroy(dtrace_hdl_t *dtp)
284178173Simp{
285178173Simp	int i;
286178173Simp
287178173Simp	for (i = 0; i < dtp->dt_maxformat; i++) {
288178173Simp		if (dtp->dt_formats[i] != NULL)
289178173Simp			dt_printf_destroy(dtp->dt_formats[i]);
290178173Simp	}
291178173Simp
292178173Simp	free(dtp->dt_formats);
293178173Simp	dtp->dt_formats = NULL;
294178173Simp}
295178173Simp
296178173Simpstatic int
297178173Simpdt_aggid_add(dtrace_hdl_t *dtp, dtrace_aggid_t id)
298178173Simp{
299178173Simp	dtrace_id_t max;
300178173Simp	dtrace_epid_t epid;
301178173Simp	int rval;
302178173Simp
303178173Simp	while (id >= (max = dtp->dt_maxagg) || dtp->dt_aggdesc == NULL) {
304178173Simp		dtrace_id_t new_max = max ? (max << 1) : 1;
305178173Simp		size_t nsize = new_max * sizeof (void *);
306178173Simp		dtrace_aggdesc_t **new_aggdesc;
307178173Simp
308178173Simp		if ((new_aggdesc = malloc(nsize)) == NULL)
309178173Simp			return (dt_set_errno(dtp, EDT_NOMEM));
310178173Simp
311178173Simp		bzero(new_aggdesc, nsize);
312178173Simp
313178173Simp		if (dtp->dt_aggdesc != NULL) {
314178173Simp			bcopy(dtp->dt_aggdesc, new_aggdesc,
315178173Simp			    max * sizeof (void *));
316178173Simp			free(dtp->dt_aggdesc);
317178173Simp		}
318178173Simp
319178173Simp		dtp->dt_aggdesc = new_aggdesc;
320178173Simp		dtp->dt_maxagg = new_max;
321178173Simp	}
322178173Simp
323178173Simp	if (dtp->dt_aggdesc[id] == NULL) {
324178173Simp		dtrace_aggdesc_t *agg, *nagg;
325178173Simp
326178173Simp		if ((agg = malloc(sizeof (dtrace_aggdesc_t))) == NULL)
327178173Simp			return (dt_set_errno(dtp, EDT_NOMEM));
328178173Simp
329178173Simp		bzero(agg, sizeof (dtrace_aggdesc_t));
330178173Simp		agg->dtagd_id = id;
331178173Simp		agg->dtagd_nrecs = 1;
332183173Simp
333178173Simp#if defined(sun)
334178173Simp		if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg) == -1) {
335178173Simp#else
336178173Simp		if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg) == -1) {
337178173Simp#endif
338178173Simp			rval = dt_set_errno(dtp, errno);
339178173Simp			free(agg);
340178173Simp			return (rval);
341178173Simp		}
342178173Simp
343178173Simp		if (DTRACE_SIZEOF_AGGDESC(agg) != sizeof (*agg)) {
344178173Simp			/*
345178173Simp			 * There must be more than one action.  Allocate the
346178173Simp			 * appropriate amount of space and try again.
347178173Simp			 */
348178173Simp			if ((nagg = malloc(DTRACE_SIZEOF_AGGDESC(agg))) != NULL)
349178173Simp				bcopy(agg, nagg, sizeof (*agg));
350178173Simp
351178173Simp			free(agg);
352178173Simp
353183173Simp			if ((agg = nagg) == NULL)
354178173Simp				return (dt_set_errno(dtp, EDT_NOMEM));
355178173Simp
356178173Simp#if defined(sun)
357178173Simp			rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg);
358178173Simp#else
359178173Simp			rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg);
360178173Simp#endif
361178173Simp
362178173Simp			if (rval == -1) {
363178173Simp				rval = dt_set_errno(dtp, errno);
364178173Simp				free(agg);
365178173Simp				return (rval);
366178173Simp			}
367178173Simp		}
368178173Simp
369178173Simp		/*
370178173Simp		 * If we have a uarg, it's a pointer to the compiler-generated
371178173Simp		 * statement; we'll use this value to get the name and
372178173Simp		 * compiler-generated variable ID for the aggregation.  If
373178173Simp		 * we're grabbing an anonymous enabling, this pointer value
374178173Simp		 * is obviously meaningless -- and in this case, we can't
375178173Simp		 * provide the compiler-generated aggregation information.
376178173Simp		 */
377178173Simp		if (dtp->dt_options[DTRACEOPT_GRABANON] == DTRACEOPT_UNSET &&
378178173Simp		    agg->dtagd_rec[0].dtrd_uarg != 0) {
379178173Simp			dtrace_stmtdesc_t *sdp;
380178173Simp			dt_ident_t *aid;
381178173Simp
382178173Simp			sdp = (dtrace_stmtdesc_t *)(uintptr_t)
383178173Simp			    agg->dtagd_rec[0].dtrd_uarg;
384178173Simp			aid = sdp->dtsd_aggdata;
385178173Simp			agg->dtagd_name = aid->di_name;
386178173Simp			agg->dtagd_varid = aid->di_id;
387178173Simp		} else {
388178173Simp			agg->dtagd_varid = DTRACE_AGGVARIDNONE;
389178173Simp		}
390178173Simp
391178173Simp		if ((epid = agg->dtagd_epid) >= dtp->dt_maxprobe ||
392178173Simp		    dtp->dt_pdesc[epid] == NULL) {
393178173Simp			if ((rval = dt_epid_add(dtp, epid)) != 0) {
394178173Simp				free(agg);
395178173Simp				return (rval);
396178173Simp			}
397178173Simp		}
398178173Simp
399178173Simp		dtp->dt_aggdesc[id] = agg;
400178173Simp	}
401178173Simp
402178173Simp	return (0);
403178173Simp}
404178173Simp
405178173Simpint
406178173Simpdt_aggid_lookup(dtrace_hdl_t *dtp, dtrace_aggid_t aggid,
407178173Simp    dtrace_aggdesc_t **adp)
408178173Simp{
409178173Simp	int rval;
410178173Simp
411178173Simp	if (aggid >= dtp->dt_maxagg || dtp->dt_aggdesc[aggid] == NULL) {
412178173Simp		if ((rval = dt_aggid_add(dtp, aggid)) != 0)
413178173Simp			return (rval);
414178173Simp	}
415178173Simp
416178173Simp	assert(aggid < dtp->dt_maxagg);
417178173Simp	assert(dtp->dt_aggdesc[aggid] != NULL);
418178173Simp	*adp = dtp->dt_aggdesc[aggid];
419178173Simp
420178173Simp	return (0);
421178173Simp}
422178173Simp
423178173Simpvoid
424178173Simpdt_aggid_destroy(dtrace_hdl_t *dtp)
425178173Simp{
426178173Simp	size_t i;
427178173Simp
428178173Simp	assert((dtp->dt_aggdesc != NULL && dtp->dt_maxagg != 0) ||
429178173Simp	    (dtp->dt_aggdesc == NULL && dtp->dt_maxagg == 0));
430178173Simp
431178173Simp	if (dtp->dt_aggdesc == NULL)
432178173Simp		return;
433178173Simp
434178173Simp	for (i = 0; i < dtp->dt_maxagg; i++) {
435178173Simp		if (dtp->dt_aggdesc[i] != NULL)
436178173Simp			free(dtp->dt_aggdesc[i]);
437178173Simp	}
438178173Simp
439178173Simp	free(dtp->dt_aggdesc);
440178173Simp	dtp->dt_aggdesc = NULL;
441178173Simp	dtp->dt_maxagg = 0;
442178173Simp}
443178173Simp