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