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