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