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