]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - cddl/contrib/opensolaris/lib/libdtrace/common/dt_map.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / cddl / contrib / opensolaris / lib / libdtrace / common / dt_map.c
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
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
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 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
232 err:
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
244 int
245 dt_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
264 void
265 dt_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
295 void *
296 dt_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
307 void
308 dt_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
321 static int
322 dt_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
430 int
431 dt_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
448 void
449 dt_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
469 const char *
470 dt_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
481 void
482 dt_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 }