dt_map.c revision 270214
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/*
27 * Copyright (c) 2011 by Delphix. All rights reserved.
28 */
29
30#include <stdlib.h>
31#include <strings.h>
32#include <errno.h>
33#include <unistd.h>
34#include <assert.h>
35
36#include <dt_impl.h>
37#include <dt_printf.h>
38
39static int
40dt_strdata_add(dtrace_hdl_t *dtp, dtrace_recdesc_t *rec, void ***data, int *max)
41{
42	int maxformat, rval;
43	dtrace_fmtdesc_t fmt;
44	void *result;
45
46	if (rec->dtrd_format == 0)
47		return (0);
48
49	if (rec->dtrd_format <= *max &&
50	    (*data)[rec->dtrd_format - 1] != NULL) {
51		return (0);
52	}
53
54	bzero(&fmt, sizeof (fmt));
55	fmt.dtfd_format = rec->dtrd_format;
56	fmt.dtfd_string = NULL;
57	fmt.dtfd_length = 0;
58
59	if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1)
60		return (dt_set_errno(dtp, errno));
61
62	if ((fmt.dtfd_string = dt_alloc(dtp, fmt.dtfd_length)) == NULL)
63		return (dt_set_errno(dtp, EDT_NOMEM));
64
65	if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
66		rval = dt_set_errno(dtp, errno);
67		free(fmt.dtfd_string);
68		return (rval);
69	}
70
71	while (rec->dtrd_format > (maxformat = *max)) {
72		int new_max = maxformat ? (maxformat << 1) : 1;
73		size_t nsize = new_max * sizeof (void *);
74		size_t osize = maxformat * sizeof (void *);
75		void **new_data = dt_zalloc(dtp, nsize);
76
77		if (new_data == NULL) {
78			dt_free(dtp, fmt.dtfd_string);
79			return (dt_set_errno(dtp, EDT_NOMEM));
80		}
81
82		bcopy(*data, new_data, osize);
83		free(*data);
84
85		*data = new_data;
86		*max = new_max;
87	}
88
89	switch (rec->dtrd_action) {
90	case DTRACEACT_DIFEXPR:
91		result = fmt.dtfd_string;
92		break;
93	case DTRACEACT_PRINTA:
94		result = dtrace_printa_create(dtp, fmt.dtfd_string);
95		dt_free(dtp, fmt.dtfd_string);
96		break;
97	default:
98		result = dtrace_printf_create(dtp, fmt.dtfd_string);
99		dt_free(dtp, fmt.dtfd_string);
100		break;
101	}
102
103	if (result == NULL)
104		return (-1);
105
106	(*data)[rec->dtrd_format - 1] = result;
107
108	return (0);
109}
110
111static int
112dt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id)
113{
114	dtrace_id_t max;
115	int rval, i;
116	dtrace_eprobedesc_t *enabled, *nenabled;
117	dtrace_probedesc_t *probe;
118
119	while (id >= (max = dtp->dt_maxprobe) || dtp->dt_pdesc == NULL) {
120		dtrace_id_t new_max = max ? (max << 1) : 1;
121		size_t nsize = new_max * sizeof (void *);
122		dtrace_probedesc_t **new_pdesc;
123		dtrace_eprobedesc_t **new_edesc;
124
125		if ((new_pdesc = malloc(nsize)) == NULL ||
126		    (new_edesc = malloc(nsize)) == NULL) {
127			free(new_pdesc);
128			return (dt_set_errno(dtp, EDT_NOMEM));
129		}
130
131		bzero(new_pdesc, nsize);
132		bzero(new_edesc, nsize);
133
134		if (dtp->dt_pdesc != NULL) {
135			size_t osize = max * sizeof (void *);
136
137			bcopy(dtp->dt_pdesc, new_pdesc, osize);
138			free(dtp->dt_pdesc);
139
140			bcopy(dtp->dt_edesc, new_edesc, osize);
141			free(dtp->dt_edesc);
142		}
143
144		dtp->dt_pdesc = new_pdesc;
145		dtp->dt_edesc = new_edesc;
146		dtp->dt_maxprobe = new_max;
147	}
148
149	if (dtp->dt_pdesc[id] != NULL)
150		return (0);
151
152	if ((enabled = malloc(sizeof (dtrace_eprobedesc_t))) == NULL)
153		return (dt_set_errno(dtp, EDT_NOMEM));
154
155	bzero(enabled, sizeof (dtrace_eprobedesc_t));
156	enabled->dtepd_epid = id;
157	enabled->dtepd_nrecs = 1;
158
159#if defined(sun)
160	if (dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled) == -1) {
161#else
162	if (dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled) == -1) {
163#endif
164		rval = dt_set_errno(dtp, errno);
165		free(enabled);
166		return (rval);
167	}
168
169	if (DTRACE_SIZEOF_EPROBEDESC(enabled) != sizeof (*enabled)) {
170		/*
171		 * There must be more than one action.  Allocate the
172		 * appropriate amount of space and try again.
173		 */
174		if ((nenabled =
175		    malloc(DTRACE_SIZEOF_EPROBEDESC(enabled))) != NULL)
176			bcopy(enabled, nenabled, sizeof (*enabled));
177
178		free(enabled);
179
180		if ((enabled = nenabled) == NULL)
181			return (dt_set_errno(dtp, EDT_NOMEM));
182
183#if defined(sun)
184		rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled);
185#else
186		rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled);
187#endif
188
189		if (rval == -1) {
190			rval = dt_set_errno(dtp, errno);
191			free(enabled);
192			return (rval);
193		}
194	}
195
196	if ((probe = malloc(sizeof (dtrace_probedesc_t))) == NULL) {
197		free(enabled);
198		return (dt_set_errno(dtp, EDT_NOMEM));
199	}
200
201	probe->dtpd_id = enabled->dtepd_probeid;
202
203	if (dt_ioctl(dtp, DTRACEIOC_PROBES, probe) == -1) {
204		rval = dt_set_errno(dtp, errno);
205		goto err;
206	}
207
208	for (i = 0; i < enabled->dtepd_nrecs; i++) {
209		dtrace_recdesc_t *rec = &enabled->dtepd_rec[i];
210
211		if (DTRACEACT_ISPRINTFLIKE(rec->dtrd_action)) {
212			if (dt_strdata_add(dtp, rec, &dtp->dt_formats,
213			    &dtp->dt_maxformat) != 0) {
214				rval = -1;
215				goto err;
216			}
217		} else if (rec->dtrd_action == DTRACEACT_DIFEXPR) {
218			if (dt_strdata_add(dtp, rec,
219			    (void ***)&dtp->dt_strdata,
220			    &dtp->dt_maxstrdata) != 0) {
221				rval = -1;
222				goto err;
223			}
224		}
225
226	}
227
228	dtp->dt_pdesc[id] = probe;
229	dtp->dt_edesc[id] = enabled;
230
231	return (0);
232
233err:
234	/*
235	 * If we failed, free our allocated probes.  Note that if we failed
236	 * while allocating formats, we aren't going to free formats that
237	 * we have already allocated.  This is okay; these formats are
238	 * hanging off of dt_formats and will therefore not be leaked.
239	 */
240	free(enabled);
241	free(probe);
242	return (rval);
243}
244
245int
246dt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid,
247    dtrace_eprobedesc_t **epdp, dtrace_probedesc_t **pdp)
248{
249	int rval;
250
251	if (epid >= dtp->dt_maxprobe || dtp->dt_pdesc[epid] == NULL) {
252		if ((rval = dt_epid_add(dtp, epid)) != 0)
253			return (rval);
254	}
255
256	assert(epid < dtp->dt_maxprobe);
257	assert(dtp->dt_edesc[epid] != NULL);
258	assert(dtp->dt_pdesc[epid] != NULL);
259	*epdp = dtp->dt_edesc[epid];
260	*pdp = dtp->dt_pdesc[epid];
261
262	return (0);
263}
264
265void
266dt_epid_destroy(dtrace_hdl_t *dtp)
267{
268	size_t i;
269
270	assert((dtp->dt_pdesc != NULL && dtp->dt_edesc != NULL &&
271	    dtp->dt_maxprobe > 0) || (dtp->dt_pdesc == NULL &&
272	    dtp->dt_edesc == NULL && dtp->dt_maxprobe == 0));
273
274	if (dtp->dt_pdesc == NULL)
275		return;
276
277	for (i = 0; i < dtp->dt_maxprobe; i++) {
278		if (dtp->dt_edesc[i] == NULL) {
279			assert(dtp->dt_pdesc[i] == NULL);
280			continue;
281		}
282
283		assert(dtp->dt_pdesc[i] != NULL);
284		free(dtp->dt_edesc[i]);
285		free(dtp->dt_pdesc[i]);
286	}
287
288	free(dtp->dt_pdesc);
289	dtp->dt_pdesc = NULL;
290
291	free(dtp->dt_edesc);
292	dtp->dt_edesc = NULL;
293	dtp->dt_maxprobe = 0;
294}
295
296void *
297dt_format_lookup(dtrace_hdl_t *dtp, int format)
298{
299	if (format == 0 || format > dtp->dt_maxformat)
300		return (NULL);
301
302	if (dtp->dt_formats == NULL)
303		return (NULL);
304
305	return (dtp->dt_formats[format - 1]);
306}
307
308void
309dt_format_destroy(dtrace_hdl_t *dtp)
310{
311	int i;
312
313	for (i = 0; i < dtp->dt_maxformat; i++) {
314		if (dtp->dt_formats[i] != NULL)
315			dt_printf_destroy(dtp->dt_formats[i]);
316	}
317
318	free(dtp->dt_formats);
319	dtp->dt_formats = NULL;
320}
321
322static int
323dt_aggid_add(dtrace_hdl_t *dtp, dtrace_aggid_t id)
324{
325	dtrace_id_t max;
326	dtrace_epid_t epid;
327	int rval;
328
329	while (id >= (max = dtp->dt_maxagg) || dtp->dt_aggdesc == NULL) {
330		dtrace_id_t new_max = max ? (max << 1) : 1;
331		size_t nsize = new_max * sizeof (void *);
332		dtrace_aggdesc_t **new_aggdesc;
333
334		if ((new_aggdesc = malloc(nsize)) == NULL)
335			return (dt_set_errno(dtp, EDT_NOMEM));
336
337		bzero(new_aggdesc, nsize);
338
339		if (dtp->dt_aggdesc != NULL) {
340			bcopy(dtp->dt_aggdesc, new_aggdesc,
341			    max * sizeof (void *));
342			free(dtp->dt_aggdesc);
343		}
344
345		dtp->dt_aggdesc = new_aggdesc;
346		dtp->dt_maxagg = new_max;
347	}
348
349	if (dtp->dt_aggdesc[id] == NULL) {
350		dtrace_aggdesc_t *agg, *nagg;
351
352		if ((agg = malloc(sizeof (dtrace_aggdesc_t))) == NULL)
353			return (dt_set_errno(dtp, EDT_NOMEM));
354
355		bzero(agg, sizeof (dtrace_aggdesc_t));
356		agg->dtagd_id = id;
357		agg->dtagd_nrecs = 1;
358
359#if defined(sun)
360		if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg) == -1) {
361#else
362		if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg) == -1) {
363#endif
364			rval = dt_set_errno(dtp, errno);
365			free(agg);
366			return (rval);
367		}
368
369		if (DTRACE_SIZEOF_AGGDESC(agg) != sizeof (*agg)) {
370			/*
371			 * There must be more than one action.  Allocate the
372			 * appropriate amount of space and try again.
373			 */
374			if ((nagg = malloc(DTRACE_SIZEOF_AGGDESC(agg))) != NULL)
375				bcopy(agg, nagg, sizeof (*agg));
376
377			free(agg);
378
379			if ((agg = nagg) == NULL)
380				return (dt_set_errno(dtp, EDT_NOMEM));
381
382#if defined(sun)
383			rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg);
384#else
385			rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg);
386#endif
387
388			if (rval == -1) {
389				rval = dt_set_errno(dtp, errno);
390				free(agg);
391				return (rval);
392			}
393		}
394
395		/*
396		 * If we have a uarg, it's a pointer to the compiler-generated
397		 * statement; we'll use this value to get the name and
398		 * compiler-generated variable ID for the aggregation.  If
399		 * we're grabbing an anonymous enabling, this pointer value
400		 * is obviously meaningless -- and in this case, we can't
401		 * provide the compiler-generated aggregation information.
402		 */
403		if (dtp->dt_options[DTRACEOPT_GRABANON] == DTRACEOPT_UNSET &&
404		    agg->dtagd_rec[0].dtrd_uarg != 0) {
405			dtrace_stmtdesc_t *sdp;
406			dt_ident_t *aid;
407
408			sdp = (dtrace_stmtdesc_t *)(uintptr_t)
409			    agg->dtagd_rec[0].dtrd_uarg;
410			aid = sdp->dtsd_aggdata;
411			agg->dtagd_name = aid->di_name;
412			agg->dtagd_varid = aid->di_id;
413		} else {
414			agg->dtagd_varid = DTRACE_AGGVARIDNONE;
415		}
416
417		if ((epid = agg->dtagd_epid) >= dtp->dt_maxprobe ||
418		    dtp->dt_pdesc[epid] == NULL) {
419			if ((rval = dt_epid_add(dtp, epid)) != 0) {
420				free(agg);
421				return (rval);
422			}
423		}
424
425		dtp->dt_aggdesc[id] = agg;
426	}
427
428	return (0);
429}
430
431int
432dt_aggid_lookup(dtrace_hdl_t *dtp, dtrace_aggid_t aggid,
433    dtrace_aggdesc_t **adp)
434{
435	int rval;
436
437	if (aggid >= dtp->dt_maxagg || dtp->dt_aggdesc[aggid] == NULL) {
438		if ((rval = dt_aggid_add(dtp, aggid)) != 0)
439			return (rval);
440	}
441
442	assert(aggid < dtp->dt_maxagg);
443	assert(dtp->dt_aggdesc[aggid] != NULL);
444	*adp = dtp->dt_aggdesc[aggid];
445
446	return (0);
447}
448
449void
450dt_aggid_destroy(dtrace_hdl_t *dtp)
451{
452	size_t i;
453
454	assert((dtp->dt_aggdesc != NULL && dtp->dt_maxagg != 0) ||
455	    (dtp->dt_aggdesc == NULL && dtp->dt_maxagg == 0));
456
457	if (dtp->dt_aggdesc == NULL)
458		return;
459
460	for (i = 0; i < dtp->dt_maxagg; i++) {
461		if (dtp->dt_aggdesc[i] != NULL)
462			free(dtp->dt_aggdesc[i]);
463	}
464
465	free(dtp->dt_aggdesc);
466	dtp->dt_aggdesc = NULL;
467	dtp->dt_maxagg = 0;
468}
469
470const char *
471dt_strdata_lookup(dtrace_hdl_t *dtp, int idx)
472{
473	if (idx == 0 || idx > dtp->dt_maxstrdata)
474		return (NULL);
475
476	if (dtp->dt_strdata == NULL)
477		return (NULL);
478
479	return (dtp->dt_strdata[idx - 1]);
480}
481
482void
483dt_strdata_destroy(dtrace_hdl_t *dtp)
484{
485	int i;
486
487	for (i = 0; i < dtp->dt_maxstrdata; i++) {
488		free(dtp->dt_strdata[i]);
489	}
490
491	free(dtp->dt_strdata);
492	dtp->dt_strdata = NULL;
493}
494