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