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