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
26248708Spfg/*
27248708Spfg * Copyright (c) 2011 by Delphix. All rights reserved.
28248708Spfg */
29178479Sjb
30178479Sjb#include <stdlib.h>
31178479Sjb#include <strings.h>
32178479Sjb#include <errno.h>
33178479Sjb#include <unistd.h>
34178479Sjb#include <assert.h>
35178479Sjb
36178479Sjb#include <dt_impl.h>
37178479Sjb#include <dt_printf.h>
38178479Sjb
39178479Sjbstatic int
40248708Spfgdt_strdata_add(dtrace_hdl_t *dtp, dtrace_recdesc_t *rec, void ***data, int *max)
41248708Spfg{
42270214Smarkj	int maxformat, rval;
43248708Spfg	dtrace_fmtdesc_t fmt;
44248708Spfg	void *result;
45248708Spfg
46248708Spfg	if (rec->dtrd_format == 0)
47248708Spfg		return (0);
48248708Spfg
49248708Spfg	if (rec->dtrd_format <= *max &&
50248708Spfg	    (*data)[rec->dtrd_format - 1] != NULL) {
51248708Spfg		return (0);
52248708Spfg	}
53248708Spfg
54248708Spfg	bzero(&fmt, sizeof (fmt));
55248708Spfg	fmt.dtfd_format = rec->dtrd_format;
56248708Spfg	fmt.dtfd_string = NULL;
57248708Spfg	fmt.dtfd_length = 0;
58248708Spfg
59248708Spfg	if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1)
60248708Spfg		return (dt_set_errno(dtp, errno));
61248708Spfg
62248708Spfg	if ((fmt.dtfd_string = dt_alloc(dtp, fmt.dtfd_length)) == NULL)
63248708Spfg		return (dt_set_errno(dtp, EDT_NOMEM));
64248708Spfg
65248708Spfg	if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
66270214Smarkj		rval = dt_set_errno(dtp, errno);
67248708Spfg		free(fmt.dtfd_string);
68270214Smarkj		return (rval);
69248708Spfg	}
70248708Spfg
71248708Spfg	while (rec->dtrd_format > (maxformat = *max)) {
72248708Spfg		int new_max = maxformat ? (maxformat << 1) : 1;
73248708Spfg		size_t nsize = new_max * sizeof (void *);
74248708Spfg		size_t osize = maxformat * sizeof (void *);
75248708Spfg		void **new_data = dt_zalloc(dtp, nsize);
76248708Spfg
77248708Spfg		if (new_data == NULL) {
78248708Spfg			dt_free(dtp, fmt.dtfd_string);
79248708Spfg			return (dt_set_errno(dtp, EDT_NOMEM));
80248708Spfg		}
81248708Spfg
82248708Spfg		bcopy(*data, new_data, osize);
83248708Spfg		free(*data);
84248708Spfg
85248708Spfg		*data = new_data;
86248708Spfg		*max = new_max;
87248708Spfg	}
88248708Spfg
89248708Spfg	switch (rec->dtrd_action) {
90248708Spfg	case DTRACEACT_DIFEXPR:
91248708Spfg		result = fmt.dtfd_string;
92248708Spfg		break;
93248708Spfg	case DTRACEACT_PRINTA:
94248708Spfg		result = dtrace_printa_create(dtp, fmt.dtfd_string);
95248708Spfg		dt_free(dtp, fmt.dtfd_string);
96248708Spfg		break;
97248708Spfg	default:
98248708Spfg		result = dtrace_printf_create(dtp, fmt.dtfd_string);
99248708Spfg		dt_free(dtp, fmt.dtfd_string);
100248708Spfg		break;
101248708Spfg	}
102248708Spfg
103248708Spfg	if (result == NULL)
104248708Spfg		return (-1);
105248708Spfg
106248708Spfg	(*data)[rec->dtrd_format - 1] = result;
107248708Spfg
108248708Spfg	return (0);
109248708Spfg}
110248708Spfg
111248708Spfgstatic int
112178479Sjbdt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id)
113178479Sjb{
114178479Sjb	dtrace_id_t max;
115248708Spfg	int rval, i;
116178479Sjb	dtrace_eprobedesc_t *enabled, *nenabled;
117178479Sjb	dtrace_probedesc_t *probe;
118178479Sjb
119178479Sjb	while (id >= (max = dtp->dt_maxprobe) || dtp->dt_pdesc == NULL) {
120178479Sjb		dtrace_id_t new_max = max ? (max << 1) : 1;
121178479Sjb		size_t nsize = new_max * sizeof (void *);
122178479Sjb		dtrace_probedesc_t **new_pdesc;
123178479Sjb		dtrace_eprobedesc_t **new_edesc;
124178479Sjb
125178479Sjb		if ((new_pdesc = malloc(nsize)) == NULL ||
126178479Sjb		    (new_edesc = malloc(nsize)) == NULL) {
127178479Sjb			free(new_pdesc);
128178479Sjb			return (dt_set_errno(dtp, EDT_NOMEM));
129178479Sjb		}
130178479Sjb
131178479Sjb		bzero(new_pdesc, nsize);
132178479Sjb		bzero(new_edesc, nsize);
133178479Sjb
134178479Sjb		if (dtp->dt_pdesc != NULL) {
135178479Sjb			size_t osize = max * sizeof (void *);
136178479Sjb
137178479Sjb			bcopy(dtp->dt_pdesc, new_pdesc, osize);
138178479Sjb			free(dtp->dt_pdesc);
139178479Sjb
140178479Sjb			bcopy(dtp->dt_edesc, new_edesc, osize);
141178479Sjb			free(dtp->dt_edesc);
142178479Sjb		}
143178479Sjb
144178479Sjb		dtp->dt_pdesc = new_pdesc;
145178479Sjb		dtp->dt_edesc = new_edesc;
146178479Sjb		dtp->dt_maxprobe = new_max;
147178479Sjb	}
148178479Sjb
149178479Sjb	if (dtp->dt_pdesc[id] != NULL)
150178479Sjb		return (0);
151178479Sjb
152178479Sjb	if ((enabled = malloc(sizeof (dtrace_eprobedesc_t))) == NULL)
153178479Sjb		return (dt_set_errno(dtp, EDT_NOMEM));
154178479Sjb
155178479Sjb	bzero(enabled, sizeof (dtrace_eprobedesc_t));
156178479Sjb	enabled->dtepd_epid = id;
157178479Sjb	enabled->dtepd_nrecs = 1;
158178479Sjb
159297077Smav#ifdef illumos
160178479Sjb	if (dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled) == -1) {
161178562Sjb#else
162178562Sjb	if (dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled) == -1) {
163178562Sjb#endif
164178479Sjb		rval = dt_set_errno(dtp, errno);
165178479Sjb		free(enabled);
166178479Sjb		return (rval);
167178479Sjb	}
168178479Sjb
169178479Sjb	if (DTRACE_SIZEOF_EPROBEDESC(enabled) != sizeof (*enabled)) {
170178479Sjb		/*
171178479Sjb		 * There must be more than one action.  Allocate the
172178479Sjb		 * appropriate amount of space and try again.
173178479Sjb		 */
174178479Sjb		if ((nenabled =
175178479Sjb		    malloc(DTRACE_SIZEOF_EPROBEDESC(enabled))) != NULL)
176178479Sjb			bcopy(enabled, nenabled, sizeof (*enabled));
177178479Sjb
178178479Sjb		free(enabled);
179178479Sjb
180178479Sjb		if ((enabled = nenabled) == NULL)
181178479Sjb			return (dt_set_errno(dtp, EDT_NOMEM));
182178479Sjb
183297077Smav#ifdef illumos
184178479Sjb		rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled);
185178562Sjb#else
186178562Sjb		rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled);
187178562Sjb#endif
188178479Sjb
189178479Sjb		if (rval == -1) {
190178479Sjb			rval = dt_set_errno(dtp, errno);
191178479Sjb			free(enabled);
192178479Sjb			return (rval);
193178479Sjb		}
194178479Sjb	}
195178479Sjb
196178479Sjb	if ((probe = malloc(sizeof (dtrace_probedesc_t))) == NULL) {
197178479Sjb		free(enabled);
198178479Sjb		return (dt_set_errno(dtp, EDT_NOMEM));
199178479Sjb	}
200178479Sjb
201178479Sjb	probe->dtpd_id = enabled->dtepd_probeid;
202178479Sjb
203178479Sjb	if (dt_ioctl(dtp, DTRACEIOC_PROBES, probe) == -1) {
204178479Sjb		rval = dt_set_errno(dtp, errno);
205178479Sjb		goto err;
206178479Sjb	}
207178479Sjb
208178479Sjb	for (i = 0; i < enabled->dtepd_nrecs; i++) {
209178479Sjb		dtrace_recdesc_t *rec = &enabled->dtepd_rec[i];
210178479Sjb
211248708Spfg		if (DTRACEACT_ISPRINTFLIKE(rec->dtrd_action)) {
212248708Spfg			if (dt_strdata_add(dtp, rec, &dtp->dt_formats,
213248708Spfg			    &dtp->dt_maxformat) != 0) {
214248708Spfg				rval = -1;
215178479Sjb				goto err;
216178479Sjb			}
217248708Spfg		} else if (rec->dtrd_action == DTRACEACT_DIFEXPR) {
218248708Spfg			if (dt_strdata_add(dtp, rec,
219248708Spfg			    (void ***)&dtp->dt_strdata,
220248708Spfg			    &dtp->dt_maxstrdata) != 0) {
221248708Spfg				rval = -1;
222248708Spfg				goto err;
223248708Spfg			}
224178479Sjb		}
225178479Sjb
226178479Sjb	}
227178479Sjb
228178479Sjb	dtp->dt_pdesc[id] = probe;
229178479Sjb	dtp->dt_edesc[id] = enabled;
230178479Sjb
231178479Sjb	return (0);
232178479Sjb
233178479Sjberr:
234178479Sjb	/*
235178479Sjb	 * If we failed, free our allocated probes.  Note that if we failed
236178479Sjb	 * while allocating formats, we aren't going to free formats that
237178479Sjb	 * we have already allocated.  This is okay; these formats are
238178479Sjb	 * hanging off of dt_formats and will therefore not be leaked.
239178479Sjb	 */
240178479Sjb	free(enabled);
241178479Sjb	free(probe);
242178479Sjb	return (rval);
243178479Sjb}
244178479Sjb
245178479Sjbint
246178479Sjbdt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid,
247178479Sjb    dtrace_eprobedesc_t **epdp, dtrace_probedesc_t **pdp)
248178479Sjb{
249178479Sjb	int rval;
250178479Sjb
251178479Sjb	if (epid >= dtp->dt_maxprobe || dtp->dt_pdesc[epid] == NULL) {
252178479Sjb		if ((rval = dt_epid_add(dtp, epid)) != 0)
253178479Sjb			return (rval);
254178479Sjb	}
255178479Sjb
256178479Sjb	assert(epid < dtp->dt_maxprobe);
257178479Sjb	assert(dtp->dt_edesc[epid] != NULL);
258178479Sjb	assert(dtp->dt_pdesc[epid] != NULL);
259178479Sjb	*epdp = dtp->dt_edesc[epid];
260178479Sjb	*pdp = dtp->dt_pdesc[epid];
261178479Sjb
262178479Sjb	return (0);
263178479Sjb}
264178479Sjb
265178479Sjbvoid
266178479Sjbdt_epid_destroy(dtrace_hdl_t *dtp)
267178479Sjb{
268178479Sjb	size_t i;
269178479Sjb
270178479Sjb	assert((dtp->dt_pdesc != NULL && dtp->dt_edesc != NULL &&
271178479Sjb	    dtp->dt_maxprobe > 0) || (dtp->dt_pdesc == NULL &&
272178479Sjb	    dtp->dt_edesc == NULL && dtp->dt_maxprobe == 0));
273178479Sjb
274178479Sjb	if (dtp->dt_pdesc == NULL)
275178479Sjb		return;
276178479Sjb
277178479Sjb	for (i = 0; i < dtp->dt_maxprobe; i++) {
278178479Sjb		if (dtp->dt_edesc[i] == NULL) {
279178479Sjb			assert(dtp->dt_pdesc[i] == NULL);
280178479Sjb			continue;
281178479Sjb		}
282178479Sjb
283178479Sjb		assert(dtp->dt_pdesc[i] != NULL);
284178479Sjb		free(dtp->dt_edesc[i]);
285178479Sjb		free(dtp->dt_pdesc[i]);
286178479Sjb	}
287178479Sjb
288178479Sjb	free(dtp->dt_pdesc);
289178479Sjb	dtp->dt_pdesc = NULL;
290178479Sjb
291178479Sjb	free(dtp->dt_edesc);
292178479Sjb	dtp->dt_edesc = NULL;
293178479Sjb	dtp->dt_maxprobe = 0;
294178479Sjb}
295178479Sjb
296178479Sjbvoid *
297178479Sjbdt_format_lookup(dtrace_hdl_t *dtp, int format)
298178479Sjb{
299178479Sjb	if (format == 0 || format > dtp->dt_maxformat)
300178479Sjb		return (NULL);
301178479Sjb
302178479Sjb	if (dtp->dt_formats == NULL)
303178479Sjb		return (NULL);
304178479Sjb
305178479Sjb	return (dtp->dt_formats[format - 1]);
306178479Sjb}
307178479Sjb
308178479Sjbvoid
309178479Sjbdt_format_destroy(dtrace_hdl_t *dtp)
310178479Sjb{
311178479Sjb	int i;
312178479Sjb
313178479Sjb	for (i = 0; i < dtp->dt_maxformat; i++) {
314178479Sjb		if (dtp->dt_formats[i] != NULL)
315178479Sjb			dt_printf_destroy(dtp->dt_formats[i]);
316178479Sjb	}
317178479Sjb
318178479Sjb	free(dtp->dt_formats);
319178479Sjb	dtp->dt_formats = NULL;
320178479Sjb}
321178479Sjb
322178479Sjbstatic int
323178479Sjbdt_aggid_add(dtrace_hdl_t *dtp, dtrace_aggid_t id)
324178479Sjb{
325178479Sjb	dtrace_id_t max;
326178479Sjb	dtrace_epid_t epid;
327178479Sjb	int rval;
328178479Sjb
329178479Sjb	while (id >= (max = dtp->dt_maxagg) || dtp->dt_aggdesc == NULL) {
330178479Sjb		dtrace_id_t new_max = max ? (max << 1) : 1;
331178479Sjb		size_t nsize = new_max * sizeof (void *);
332178479Sjb		dtrace_aggdesc_t **new_aggdesc;
333178479Sjb
334178479Sjb		if ((new_aggdesc = malloc(nsize)) == NULL)
335178479Sjb			return (dt_set_errno(dtp, EDT_NOMEM));
336178479Sjb
337178479Sjb		bzero(new_aggdesc, nsize);
338178479Sjb
339178479Sjb		if (dtp->dt_aggdesc != NULL) {
340178479Sjb			bcopy(dtp->dt_aggdesc, new_aggdesc,
341178479Sjb			    max * sizeof (void *));
342178479Sjb			free(dtp->dt_aggdesc);
343178479Sjb		}
344178479Sjb
345178479Sjb		dtp->dt_aggdesc = new_aggdesc;
346178479Sjb		dtp->dt_maxagg = new_max;
347178479Sjb	}
348178479Sjb
349178479Sjb	if (dtp->dt_aggdesc[id] == NULL) {
350178479Sjb		dtrace_aggdesc_t *agg, *nagg;
351178479Sjb
352178479Sjb		if ((agg = malloc(sizeof (dtrace_aggdesc_t))) == NULL)
353178479Sjb			return (dt_set_errno(dtp, EDT_NOMEM));
354178479Sjb
355178479Sjb		bzero(agg, sizeof (dtrace_aggdesc_t));
356178479Sjb		agg->dtagd_id = id;
357178479Sjb		agg->dtagd_nrecs = 1;
358178479Sjb
359297077Smav#ifdef illumos
360178479Sjb		if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg) == -1) {
361178562Sjb#else
362178562Sjb		if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg) == -1) {
363178562Sjb#endif
364178479Sjb			rval = dt_set_errno(dtp, errno);
365178479Sjb			free(agg);
366178479Sjb			return (rval);
367178479Sjb		}
368178479Sjb
369178479Sjb		if (DTRACE_SIZEOF_AGGDESC(agg) != sizeof (*agg)) {
370178479Sjb			/*
371178479Sjb			 * There must be more than one action.  Allocate the
372178479Sjb			 * appropriate amount of space and try again.
373178479Sjb			 */
374178479Sjb			if ((nagg = malloc(DTRACE_SIZEOF_AGGDESC(agg))) != NULL)
375178479Sjb				bcopy(agg, nagg, sizeof (*agg));
376178479Sjb
377178479Sjb			free(agg);
378178479Sjb
379178479Sjb			if ((agg = nagg) == NULL)
380178479Sjb				return (dt_set_errno(dtp, EDT_NOMEM));
381178479Sjb
382297077Smav#ifdef illumos
383178479Sjb			rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg);
384178562Sjb#else
385178562Sjb			rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg);
386178562Sjb#endif
387178479Sjb
388178479Sjb			if (rval == -1) {
389178479Sjb				rval = dt_set_errno(dtp, errno);
390178479Sjb				free(agg);
391178479Sjb				return (rval);
392178479Sjb			}
393178479Sjb		}
394178479Sjb
395178479Sjb		/*
396178479Sjb		 * If we have a uarg, it's a pointer to the compiler-generated
397178479Sjb		 * statement; we'll use this value to get the name and
398178479Sjb		 * compiler-generated variable ID for the aggregation.  If
399178479Sjb		 * we're grabbing an anonymous enabling, this pointer value
400178479Sjb		 * is obviously meaningless -- and in this case, we can't
401178479Sjb		 * provide the compiler-generated aggregation information.
402178479Sjb		 */
403178479Sjb		if (dtp->dt_options[DTRACEOPT_GRABANON] == DTRACEOPT_UNSET &&
404178562Sjb		    agg->dtagd_rec[0].dtrd_uarg != 0) {
405178479Sjb			dtrace_stmtdesc_t *sdp;
406178479Sjb			dt_ident_t *aid;
407178479Sjb
408178479Sjb			sdp = (dtrace_stmtdesc_t *)(uintptr_t)
409178479Sjb			    agg->dtagd_rec[0].dtrd_uarg;
410178479Sjb			aid = sdp->dtsd_aggdata;
411178479Sjb			agg->dtagd_name = aid->di_name;
412178479Sjb			agg->dtagd_varid = aid->di_id;
413178479Sjb		} else {
414178479Sjb			agg->dtagd_varid = DTRACE_AGGVARIDNONE;
415178479Sjb		}
416178479Sjb
417178479Sjb		if ((epid = agg->dtagd_epid) >= dtp->dt_maxprobe ||
418178479Sjb		    dtp->dt_pdesc[epid] == NULL) {
419178479Sjb			if ((rval = dt_epid_add(dtp, epid)) != 0) {
420178479Sjb				free(agg);
421178479Sjb				return (rval);
422178479Sjb			}
423178479Sjb		}
424178479Sjb
425178479Sjb		dtp->dt_aggdesc[id] = agg;
426178479Sjb	}
427178479Sjb
428178479Sjb	return (0);
429178479Sjb}
430178479Sjb
431178479Sjbint
432178479Sjbdt_aggid_lookup(dtrace_hdl_t *dtp, dtrace_aggid_t aggid,
433178479Sjb    dtrace_aggdesc_t **adp)
434178479Sjb{
435178479Sjb	int rval;
436178479Sjb
437178479Sjb	if (aggid >= dtp->dt_maxagg || dtp->dt_aggdesc[aggid] == NULL) {
438178479Sjb		if ((rval = dt_aggid_add(dtp, aggid)) != 0)
439178479Sjb			return (rval);
440178479Sjb	}
441178479Sjb
442178479Sjb	assert(aggid < dtp->dt_maxagg);
443178479Sjb	assert(dtp->dt_aggdesc[aggid] != NULL);
444178479Sjb	*adp = dtp->dt_aggdesc[aggid];
445178479Sjb
446178479Sjb	return (0);
447178479Sjb}
448178479Sjb
449178479Sjbvoid
450178479Sjbdt_aggid_destroy(dtrace_hdl_t *dtp)
451178479Sjb{
452178479Sjb	size_t i;
453178479Sjb
454178479Sjb	assert((dtp->dt_aggdesc != NULL && dtp->dt_maxagg != 0) ||
455178479Sjb	    (dtp->dt_aggdesc == NULL && dtp->dt_maxagg == 0));
456178479Sjb
457178479Sjb	if (dtp->dt_aggdesc == NULL)
458178479Sjb		return;
459178479Sjb
460178479Sjb	for (i = 0; i < dtp->dt_maxagg; i++) {
461178479Sjb		if (dtp->dt_aggdesc[i] != NULL)
462178479Sjb			free(dtp->dt_aggdesc[i]);
463178479Sjb	}
464178479Sjb
465178479Sjb	free(dtp->dt_aggdesc);
466178479Sjb	dtp->dt_aggdesc = NULL;
467178479Sjb	dtp->dt_maxagg = 0;
468178479Sjb}
469248708Spfg
470248708Spfgconst char *
471248708Spfgdt_strdata_lookup(dtrace_hdl_t *dtp, int idx)
472248708Spfg{
473248708Spfg	if (idx == 0 || idx > dtp->dt_maxstrdata)
474248708Spfg		return (NULL);
475248708Spfg
476248708Spfg	if (dtp->dt_strdata == NULL)
477248708Spfg		return (NULL);
478248708Spfg
479248708Spfg	return (dtp->dt_strdata[idx - 1]);
480248708Spfg}
481248708Spfg
482248708Spfgvoid
483248708Spfgdt_strdata_destroy(dtrace_hdl_t *dtp)
484248708Spfg{
485248708Spfg	int i;
486248708Spfg
487248708Spfg	for (i = 0; i < dtp->dt_maxstrdata; i++) {
488248708Spfg		free(dtp->dt_strdata[i]);
489248708Spfg	}
490248708Spfg
491248708Spfg	free(dtp->dt_strdata);
492248708Spfg	dtp->dt_strdata = NULL;
493248708Spfg}
494