]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - cddl/contrib/opensolaris/lib/libdtrace/common/dt_program.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_program.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 /*
23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright (c) 2011 by Delphix. All rights reserved.
25  */
26
27 #include <unistd.h>
28 #include <strings.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <assert.h>
32 #include <ctype.h>
33 #if defined(sun)
34 #include <alloca.h>
35 #endif
36
37 #include <dt_impl.h>
38 #include <dt_program.h>
39 #include <dt_printf.h>
40 #include <dt_provider.h>
41
42 dtrace_prog_t *
43 dt_program_create(dtrace_hdl_t *dtp)
44 {
45         dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t));
46
47         if (pgp != NULL) {
48                 dt_list_append(&dtp->dt_programs, pgp);
49         } else {
50                 (void) dt_set_errno(dtp, EDT_NOMEM);
51                 return (NULL);
52         }
53
54         /*
55          * By default, programs start with DOF version 1 so that output files
56          * containing DOF are backward compatible. If a program requires new
57          * DOF features, the version is increased as needed.
58          */
59         pgp->dp_dofversion = DOF_VERSION_1;
60
61         return (pgp);
62 }
63
64 void
65 dt_program_destroy(dtrace_hdl_t *dtp, dtrace_prog_t *pgp)
66 {
67         dt_stmt_t *stp, *next;
68         uint_t i;
69
70         for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
71                 next = dt_list_next(stp);
72                 dtrace_stmt_destroy(dtp, stp->ds_desc);
73                 dt_free(dtp, stp);
74         }
75
76         for (i = 0; i < pgp->dp_xrefslen; i++)
77                 dt_free(dtp, pgp->dp_xrefs[i]);
78
79         dt_free(dtp, pgp->dp_xrefs);
80         dt_list_delete(&dtp->dt_programs, pgp);
81         dt_free(dtp, pgp);
82 }
83
84 /*ARGSUSED*/
85 void
86 dtrace_program_info(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
87     dtrace_proginfo_t *pip)
88 {
89         dt_stmt_t *stp;
90         dtrace_actdesc_t *ap;
91         dtrace_ecbdesc_t *last = NULL;
92
93         if (pip == NULL)
94                 return;
95
96         bzero(pip, sizeof (dtrace_proginfo_t));
97
98         if (dt_list_next(&pgp->dp_stmts) != NULL) {
99                 pip->dpi_descattr = _dtrace_maxattr;
100                 pip->dpi_stmtattr = _dtrace_maxattr;
101         } else {
102                 pip->dpi_descattr = _dtrace_defattr;
103                 pip->dpi_stmtattr = _dtrace_defattr;
104         }
105
106         for (stp = dt_list_next(&pgp->dp_stmts); stp; stp = dt_list_next(stp)) {
107                 dtrace_ecbdesc_t *edp = stp->ds_desc->dtsd_ecbdesc;
108
109                 if (edp == last)
110                         continue;
111                 last = edp;
112
113                 pip->dpi_descattr =
114                     dt_attr_min(stp->ds_desc->dtsd_descattr, pip->dpi_descattr);
115
116                 pip->dpi_stmtattr =
117                     dt_attr_min(stp->ds_desc->dtsd_stmtattr, pip->dpi_stmtattr);
118
119                 /*
120                  * If there aren't any actions, account for the fact that
121                  * recording the epid will generate a record.
122                  */
123                 if (edp->dted_action == NULL)
124                         pip->dpi_recgens++;
125
126                 for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
127                         if (ap->dtad_kind == DTRACEACT_SPECULATE) {
128                                 pip->dpi_speculations++;
129                                 continue;
130                         }
131
132                         if (DTRACEACT_ISAGG(ap->dtad_kind)) {
133                                 pip->dpi_recgens -= ap->dtad_arg;
134                                 pip->dpi_aggregates++;
135                                 continue;
136                         }
137
138                         if (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind))
139                                 continue;
140
141                         if (ap->dtad_kind == DTRACEACT_DIFEXPR &&
142                             ap->dtad_difo->dtdo_rtype.dtdt_kind ==
143                             DIF_TYPE_CTF &&
144                             ap->dtad_difo->dtdo_rtype.dtdt_size == 0)
145                                 continue;
146
147                         pip->dpi_recgens++;
148                 }
149         }
150 }
151
152 int
153 dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
154     dtrace_proginfo_t *pip)
155 {
156         dtrace_enable_io_t args;
157         void *dof;
158         int n, err;
159
160         dtrace_program_info(dtp, pgp, pip);
161
162         if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL)
163                 return (-1);
164
165         args.dof = dof;
166         args.n_matched = 0;
167         n = dt_ioctl(dtp, DTRACEIOC_ENABLE, &args);
168         dtrace_dof_destroy(dtp, dof);
169
170         if (n == -1) {
171                 switch (errno) {
172                 case EINVAL:
173                         err = EDT_DIFINVAL;
174                         break;
175                 case EFAULT:
176                         err = EDT_DIFFAULT;
177                         break;
178                 case E2BIG:
179                         err = EDT_DIFSIZE;
180                         break;
181                 case EBUSY:
182                         err = EDT_ENABLING_ERR;
183                         break;
184                 default:
185                         err = errno;
186                 }
187
188                 return (dt_set_errno(dtp, err));
189         }
190
191         if (pip != NULL)
192                 pip->dpi_matches += args.n_matched;
193
194         return (0);
195 }
196
197 static void
198 dt_ecbdesc_hold(dtrace_ecbdesc_t *edp)
199 {
200         edp->dted_refcnt++;
201 }
202
203 void
204 dt_ecbdesc_release(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
205 {
206         if (--edp->dted_refcnt > 0)
207                 return;
208
209         dt_difo_free(dtp, edp->dted_pred.dtpdd_difo);
210         assert(edp->dted_action == NULL);
211         dt_free(dtp, edp);
212 }
213
214 dtrace_ecbdesc_t *
215 dt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)
216 {
217         dtrace_ecbdesc_t *edp;
218
219         if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) {
220                 (void) dt_set_errno(dtp, EDT_NOMEM);
221                 return (NULL);
222         }
223
224         edp->dted_probe = *pdp;
225         dt_ecbdesc_hold(edp);
226         return (edp);
227 }
228
229 dtrace_stmtdesc_t *
230 dtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
231 {
232         dtrace_stmtdesc_t *sdp;
233
234         if ((sdp = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL)
235                 return (NULL);
236
237         dt_ecbdesc_hold(edp);
238         sdp->dtsd_ecbdesc = edp;
239         sdp->dtsd_descattr = _dtrace_defattr;
240         sdp->dtsd_stmtattr = _dtrace_defattr;
241
242         return (sdp);
243 }
244
245 dtrace_actdesc_t *
246 dtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
247 {
248         dtrace_actdesc_t *new;
249         dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
250
251         if ((new = dt_alloc(dtp, sizeof (dtrace_actdesc_t))) == NULL)
252                 return (NULL);
253
254         if (sdp->dtsd_action_last != NULL) {
255                 assert(sdp->dtsd_action != NULL);
256                 assert(sdp->dtsd_action_last->dtad_next == NULL);
257                 sdp->dtsd_action_last->dtad_next = new;
258         } else {
259                 dtrace_actdesc_t *ap = edp->dted_action;
260
261                 assert(sdp->dtsd_action == NULL);
262                 sdp->dtsd_action = new;
263
264                 while (ap != NULL && ap->dtad_next != NULL)
265                         ap = ap->dtad_next;
266
267                 if (ap == NULL)
268                         edp->dted_action = new;
269                 else
270                         ap->dtad_next = new;
271         }
272
273         sdp->dtsd_action_last = new;
274         bzero(new, sizeof (dtrace_actdesc_t));
275         new->dtad_uarg = (uintptr_t)sdp;
276
277         return (new);
278 }
279
280 int
281 dtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp)
282 {
283         dt_stmt_t *stp = dt_alloc(dtp, sizeof (dt_stmt_t));
284
285         if (stp == NULL)
286                 return (-1); /* errno is set for us */
287
288         dt_list_append(&pgp->dp_stmts, stp);
289         stp->ds_desc = sdp;
290
291         return (0);
292 }
293
294 int
295 dtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
296     dtrace_stmt_f *func, void *data)
297 {
298         dt_stmt_t *stp, *next;
299         int status = 0;
300
301         for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
302                 next = dt_list_next(stp);
303                 if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0)
304                         break;
305         }
306
307         return (status);
308 }
309
310 void
311 dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
312 {
313         dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
314
315         /*
316          * We need to remove any actions that we have on this ECB, and
317          * remove our hold on the ECB itself.
318          */
319         if (sdp->dtsd_action != NULL) {
320                 dtrace_actdesc_t *last = sdp->dtsd_action_last;
321                 dtrace_actdesc_t *ap, *next;
322
323                 assert(last != NULL);
324
325                 for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
326                         if (ap == sdp->dtsd_action)
327                                 break;
328
329                         if (ap->dtad_next == sdp->dtsd_action)
330                                 break;
331                 }
332
333                 assert(ap != NULL);
334
335                 if (ap == edp->dted_action)
336                         edp->dted_action = last->dtad_next;
337                 else
338                         ap->dtad_next = last->dtad_next;
339
340                 /*
341                  * We have now removed our action list from its ECB; we can
342                  * safely destroy the list.
343                  */
344                 last->dtad_next = NULL;
345
346                 for (ap = sdp->dtsd_action; ap != NULL; ap = next) {
347                         assert(ap->dtad_uarg == (uintptr_t)sdp);
348                         dt_difo_free(dtp, ap->dtad_difo);
349                         next = ap->dtad_next;
350                         dt_free(dtp, ap);
351                 }
352         }
353
354         if (sdp->dtsd_fmtdata != NULL)
355                 dt_printf_destroy(sdp->dtsd_fmtdata);
356         dt_free(dtp, sdp->dtsd_strdata);
357
358         dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc);
359         dt_free(dtp, sdp);
360 }
361
362 typedef struct dt_header_info {
363         dtrace_hdl_t *dthi_dtp; /* consumer handle */
364         FILE *dthi_out;         /* output file */
365         char *dthi_pmname;      /* provider macro name */
366         char *dthi_pfname;      /* provider function name */
367         int dthi_empty;         /* should we generate empty macros */
368 } dt_header_info_t;
369
370 static void
371 dt_header_fmt_macro(char *buf, const char *str)
372 {
373         for (;;) {
374                 if (islower(*str)) {
375                         *buf++ = *str++ + 'A' - 'a';
376                 } else if (*str == '-') {
377                         *buf++ = '_';
378                         str++;
379                 } else if (*str == '.') {
380                         *buf++ = '_';
381                         str++;
382                 } else if ((*buf++ = *str++) == '\0') {
383                         break;
384                 }
385         }
386 }
387
388 static void
389 dt_header_fmt_func(char *buf, const char *str)
390 {
391         for (;;) {
392                 if (*str == '-') {
393                         *buf++ = '_';
394                         *buf++ = '_';
395                         str++;
396                 } else if ((*buf++ = *str++) == '\0') {
397                         break;
398                 }
399         }
400 }
401
402 /*ARGSUSED*/
403 static int
404 dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
405 {
406         dt_header_info_t *infop = data;
407         dtrace_hdl_t *dtp = infop->dthi_dtp;
408         dt_probe_t *prp = idp->di_data;
409         dt_node_t *dnp;
410         char buf[DT_TYPE_NAMELEN];
411         char *fname;
412         const char *p;
413         int i;
414
415         p = prp->pr_name;
416         for (i = 0; (p = strchr(p, '-')) != NULL; i++)
417                 p++;
418
419         fname = alloca(strlen(prp->pr_name) + 1 + i);
420         dt_header_fmt_func(fname, prp->pr_name);
421
422         if (fprintf(infop->dthi_out, "extern void __dtrace_%s___%s(",
423             infop->dthi_pfname, fname) < 0)
424                 return (dt_set_errno(dtp, errno));
425
426         for (dnp = prp->pr_nargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) {
427                 if (fprintf(infop->dthi_out, "%s",
428                     ctf_type_name(dnp->dn_ctfp, dnp->dn_type,
429                     buf, sizeof (buf))) < 0)
430                         return (dt_set_errno(dtp, errno));
431
432                 if (i + 1 != prp->pr_nargc &&
433                     fprintf(infop->dthi_out, ", ") < 0)
434                         return (dt_set_errno(dtp, errno));
435         }
436
437         if (i == 0 && fprintf(infop->dthi_out, "void") < 0)
438                 return (dt_set_errno(dtp, errno));
439
440         if (fprintf(infop->dthi_out, ");\n") < 0)
441                 return (dt_set_errno(dtp, errno));
442
443         if (fprintf(infop->dthi_out,
444             "#ifndef\t__sparc\n"
445             "extern int __dtraceenabled_%s___%s(void);\n"
446             "#else\n"
447             "extern int __dtraceenabled_%s___%s(long);\n"
448             "#endif\n",
449             infop->dthi_pfname, fname, infop->dthi_pfname, fname) < 0)
450                 return (dt_set_errno(dtp, errno));
451
452         return (0);
453 }
454
455 /*ARGSUSED*/
456 static int
457 dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
458 {
459         dt_header_info_t *infop = data;
460         dtrace_hdl_t *dtp = infop->dthi_dtp;
461         dt_probe_t *prp = idp->di_data;
462         char *mname, *fname;
463         const char *p;
464         int i;
465
466         p = prp->pr_name;
467         for (i = 0; (p = strchr(p, '-')) != NULL; i++)
468                 p++;
469
470         mname = alloca(strlen(prp->pr_name) + 1);
471         dt_header_fmt_macro(mname, prp->pr_name);
472
473         fname = alloca(strlen(prp->pr_name) + 1 + i);
474         dt_header_fmt_func(fname, prp->pr_name);
475
476         if (fprintf(infop->dthi_out, "#define\t%s_%s(",
477             infop->dthi_pmname, mname) < 0)
478                 return (dt_set_errno(dtp, errno));
479
480         for (i = 0; i < prp->pr_nargc; i++) {
481                 if (fprintf(infop->dthi_out, "arg%d", i) < 0)
482                         return (dt_set_errno(dtp, errno));
483
484                 if (i + 1 != prp->pr_nargc &&
485                     fprintf(infop->dthi_out, ", ") < 0)
486                         return (dt_set_errno(dtp, errno));
487         }
488
489         if (!infop->dthi_empty) {
490                 if (fprintf(infop->dthi_out, ") \\\n\t") < 0)
491                         return (dt_set_errno(dtp, errno));
492
493                 if (fprintf(infop->dthi_out, "__dtrace_%s___%s(",
494                     infop->dthi_pfname, fname) < 0)
495                         return (dt_set_errno(dtp, errno));
496
497                 for (i = 0; i < prp->pr_nargc; i++) {
498                         if (fprintf(infop->dthi_out, "arg%d", i) < 0)
499                                 return (dt_set_errno(dtp, errno));
500
501                         if (i + 1 != prp->pr_nargc &&
502                             fprintf(infop->dthi_out, ", ") < 0)
503                                 return (dt_set_errno(dtp, errno));
504                 }
505         }
506
507         if (fprintf(infop->dthi_out, ")\n") < 0)
508                 return (dt_set_errno(dtp, errno));
509
510         if (!infop->dthi_empty) {
511                 if (fprintf(infop->dthi_out,
512                     "#ifndef\t__sparc\n"
513                     "#define\t%s_%s_ENABLED() \\\n"
514                     "\t__dtraceenabled_%s___%s()\n"
515                     "#else\n"
516                     "#define\t%s_%s_ENABLED() \\\n"
517                     "\t__dtraceenabled_%s___%s(0)\n"
518                     "#endif\n",
519                     infop->dthi_pmname, mname,
520                     infop->dthi_pfname, fname,
521                     infop->dthi_pmname, mname,
522                     infop->dthi_pfname, fname) < 0)
523                         return (dt_set_errno(dtp, errno));
524
525         } else {
526                 if (fprintf(infop->dthi_out, "#define\t%s_%s_ENABLED() (0)\n",
527                     infop->dthi_pmname, mname) < 0)
528                         return (dt_set_errno(dtp, errno));
529         }
530
531         return (0);
532 }
533
534 static int
535 dt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out)
536 {
537         dt_header_info_t info;
538         const char *p;
539         int i;
540
541         if (pvp->pv_flags & DT_PROVIDER_IMPL)
542                 return (0);
543
544         /*
545          * Count the instances of the '-' character since we'll need to double
546          * those up.
547          */
548         p = pvp->pv_desc.dtvd_name;
549         for (i = 0; (p = strchr(p, '-')) != NULL; i++)
550                 p++;
551
552         info.dthi_dtp = dtp;
553         info.dthi_out = out;
554         info.dthi_empty = 0;
555
556         info.dthi_pmname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1);
557         dt_header_fmt_macro(info.dthi_pmname, pvp->pv_desc.dtvd_name);
558
559         info.dthi_pfname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1 + i);
560         dt_header_fmt_func(info.dthi_pfname, pvp->pv_desc.dtvd_name);
561
562 #ifdef __FreeBSD__
563         if (fprintf(out, "#include <sys/sdt.h>\n\n") < 0)
564                 return (dt_set_errno(dtp, errno));
565 #endif
566         if (fprintf(out, "#if _DTRACE_VERSION\n\n") < 0)
567                 return (dt_set_errno(dtp, errno));
568
569         if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
570                 return (-1); /* dt_errno is set for us */
571         if (fprintf(out, "\n\n") < 0)
572                 return (dt_set_errno(dtp, errno));
573         if (dt_idhash_iter(pvp->pv_probes, dt_header_decl, &info) != 0)
574                 return (-1); /* dt_errno is set for us */
575
576         if (fprintf(out, "\n#else\n\n") < 0)
577                 return (dt_set_errno(dtp, errno));
578
579         info.dthi_empty = 1;
580
581         if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
582                 return (-1); /* dt_errno is set for us */
583
584         if (fprintf(out, "\n#endif\n\n") < 0)
585                 return (dt_set_errno(dtp, errno));
586
587         return (0);
588 }
589
590 int
591 dtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname)
592 {
593         dt_provider_t *pvp;
594         char *mfname, *p;
595
596         if (fname != NULL) {
597                 if ((p = strrchr(fname, '/')) != NULL)
598                         fname = p + 1;
599
600                 mfname = alloca(strlen(fname) + 1);
601                 dt_header_fmt_macro(mfname, fname);
602                 if (fprintf(out, "#ifndef\t_%s\n#define\t_%s\n\n",
603                     mfname, mfname) < 0)
604                         return (dt_set_errno(dtp, errno));
605         }
606
607         if (fprintf(out, "#include <unistd.h>\n\n") < 0)
608                 return (-1);
609
610         if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0)
611                 return (-1);
612
613         for (pvp = dt_list_next(&dtp->dt_provlist);
614             pvp != NULL; pvp = dt_list_next(pvp)) {
615                 if (dt_header_provider(dtp, pvp, out) != 0)
616                         return (-1); /* dt_errno is set for us */
617         }
618
619         if (fprintf(out, "\n#ifdef\t__cplusplus\n}\n#endif\n") < 0)
620                 return (dt_set_errno(dtp, errno));
621
622         if (fname != NULL && fprintf(out, "\n#endif\t/* _%s */\n", mfname) < 0)
623                 return (dt_set_errno(dtp, errno));
624
625         return (0);
626 }