]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - cddl/contrib/opensolaris/lib/libdtrace/common/dt_program.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_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 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26
27 #pragma ident   "%Z%%M% %I%     %E% SMI"
28
29 #include <unistd.h>
30 #include <strings.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <assert.h>
34 #include <ctype.h>
35 #if defined(sun)
36 #include <alloca.h>
37 #endif
38
39 #include <dt_impl.h>
40 #include <dt_program.h>
41 #include <dt_printf.h>
42 #include <dt_provider.h>
43
44 dtrace_prog_t *
45 dt_program_create(dtrace_hdl_t *dtp)
46 {
47         dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t));
48
49         if (pgp != NULL)
50                 dt_list_append(&dtp->dt_programs, pgp);
51         else
52                 (void) dt_set_errno(dtp, EDT_NOMEM);
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                 default:
182                         err = errno;
183                 }
184
185                 return (dt_set_errno(dtp, err));
186         }
187
188         if (pip != NULL)
189                 pip->dpi_matches += args.n_matched;
190
191         return (0);
192 }
193
194 static void
195 dt_ecbdesc_hold(dtrace_ecbdesc_t *edp)
196 {
197         edp->dted_refcnt++;
198 }
199
200 void
201 dt_ecbdesc_release(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
202 {
203         if (--edp->dted_refcnt > 0)
204                 return;
205
206         dt_difo_free(dtp, edp->dted_pred.dtpdd_difo);
207         assert(edp->dted_action == NULL);
208         dt_free(dtp, edp);
209 }
210
211 dtrace_ecbdesc_t *
212 dt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)
213 {
214         dtrace_ecbdesc_t *edp;
215
216         if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) {
217                 (void) dt_set_errno(dtp, EDT_NOMEM);
218                 return (NULL);
219         }
220
221         edp->dted_probe = *pdp;
222         dt_ecbdesc_hold(edp);
223         return (edp);
224 }
225
226 dtrace_stmtdesc_t *
227 dtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
228 {
229         dtrace_stmtdesc_t *sdp;
230
231         if ((sdp = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL)
232                 return (NULL);
233
234         dt_ecbdesc_hold(edp);
235         sdp->dtsd_ecbdesc = edp;
236         sdp->dtsd_descattr = _dtrace_defattr;
237         sdp->dtsd_stmtattr = _dtrace_defattr;
238
239         return (sdp);
240 }
241
242 dtrace_actdesc_t *
243 dtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
244 {
245         dtrace_actdesc_t *new;
246         dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
247
248         if ((new = dt_alloc(dtp, sizeof (dtrace_actdesc_t))) == NULL)
249                 return (NULL);
250
251         if (sdp->dtsd_action_last != NULL) {
252                 assert(sdp->dtsd_action != NULL);
253                 assert(sdp->dtsd_action_last->dtad_next == NULL);
254                 sdp->dtsd_action_last->dtad_next = new;
255         } else {
256                 dtrace_actdesc_t *ap = edp->dted_action;
257
258                 assert(sdp->dtsd_action == NULL);
259                 sdp->dtsd_action = new;
260
261                 while (ap != NULL && ap->dtad_next != NULL)
262                         ap = ap->dtad_next;
263
264                 if (ap == NULL)
265                         edp->dted_action = new;
266                 else
267                         ap->dtad_next = new;
268         }
269
270         sdp->dtsd_action_last = new;
271         bzero(new, sizeof (dtrace_actdesc_t));
272         new->dtad_uarg = (uintptr_t)sdp;
273
274         return (new);
275 }
276
277 int
278 dtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp)
279 {
280         dt_stmt_t *stp = dt_alloc(dtp, sizeof (dt_stmt_t));
281
282         if (stp == NULL)
283                 return (-1); /* errno is set for us */
284
285         dt_list_append(&pgp->dp_stmts, stp);
286         stp->ds_desc = sdp;
287
288         return (0);
289 }
290
291 int
292 dtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
293     dtrace_stmt_f *func, void *data)
294 {
295         dt_stmt_t *stp, *next;
296         int status = 0;
297
298         for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
299                 next = dt_list_next(stp);
300                 if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0)
301                         break;
302         }
303
304         return (status);
305 }
306
307 void
308 dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
309 {
310         dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
311
312         /*
313          * We need to remove any actions that we have on this ECB, and
314          * remove our hold on the ECB itself.
315          */
316         if (sdp->dtsd_action != NULL) {
317                 dtrace_actdesc_t *last = sdp->dtsd_action_last;
318                 dtrace_actdesc_t *ap, *next;
319
320                 assert(last != NULL);
321
322                 for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
323                         if (ap == sdp->dtsd_action)
324                                 break;
325
326                         if (ap->dtad_next == sdp->dtsd_action)
327                                 break;
328                 }
329
330                 assert(ap != NULL);
331
332                 if (ap == edp->dted_action)
333                         edp->dted_action = last->dtad_next;
334                 else
335                         ap->dtad_next = last->dtad_next;
336
337                 /*
338                  * We have now removed our action list from its ECB; we can
339                  * safely destroy the list.
340                  */
341                 last->dtad_next = NULL;
342
343                 for (ap = sdp->dtsd_action; ap != NULL; ap = next) {
344                         assert(ap->dtad_uarg == (uintptr_t)sdp);
345                         dt_difo_free(dtp, ap->dtad_difo);
346                         next = ap->dtad_next;
347                         dt_free(dtp, ap);
348                 }
349         }
350
351         if (sdp->dtsd_fmtdata != NULL)
352                 dt_printf_destroy(sdp->dtsd_fmtdata);
353
354         dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc);
355         dt_free(dtp, sdp);
356 }
357
358 typedef struct dt_header_info {
359         dtrace_hdl_t *dthi_dtp; /* consumer handle */
360         FILE *dthi_out;         /* output file */
361         char *dthi_pmname;      /* provider macro name */
362         char *dthi_pfname;      /* provider function name */
363         int dthi_empty;         /* should we generate empty macros */
364 } dt_header_info_t;
365
366 static void
367 dt_header_fmt_macro(char *buf, const char *str)
368 {
369         for (;;) {
370                 if (islower(*str)) {
371                         *buf++ = *str++ + 'A' - 'a';
372                 } else if (*str == '-') {
373                         *buf++ = '_';
374                         str++;
375                 } else if (*str == '.') {
376                         *buf++ = '_';
377                         str++;
378                 } else if ((*buf++ = *str++) == '\0') {
379                         break;
380                 }
381         }
382 }
383
384 static void
385 dt_header_fmt_func(char *buf, const char *str)
386 {
387         for (;;) {
388                 if (*str == '-') {
389                         *buf++ = '_';
390                         *buf++ = '_';
391                         str++;
392                 } else if ((*buf++ = *str++) == '\0') {
393                         break;
394                 }
395         }
396 }
397
398 /*ARGSUSED*/
399 static int
400 dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
401 {
402         dt_header_info_t *infop = data;
403         dtrace_hdl_t *dtp = infop->dthi_dtp;
404         dt_probe_t *prp = idp->di_data;
405         dt_node_t *dnp;
406         char buf[DT_TYPE_NAMELEN];
407         char *fname;
408         const char *p;
409         int i;
410
411         p = prp->pr_name;
412         for (i = 0; (p = strchr(p, '-')) != NULL; i++)
413                 p++;
414
415         fname = alloca(strlen(prp->pr_name) + 1 + i);
416         dt_header_fmt_func(fname, prp->pr_name);
417
418         if (fprintf(infop->dthi_out, "extern void __dtrace_%s___%s(",
419             infop->dthi_pfname, fname) < 0)
420                 return (dt_set_errno(dtp, errno));
421
422         for (dnp = prp->pr_nargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) {
423                 if (fprintf(infop->dthi_out, "%s",
424                     ctf_type_name(dnp->dn_ctfp, dnp->dn_type,
425                     buf, sizeof (buf))) < 0)
426                         return (dt_set_errno(dtp, errno));
427
428                 if (i + 1 != prp->pr_nargc &&
429                     fprintf(infop->dthi_out, ", ") < 0)
430                         return (dt_set_errno(dtp, errno));
431         }
432
433         if (i == 0 && fprintf(infop->dthi_out, "void") < 0)
434                 return (dt_set_errno(dtp, errno));
435
436         if (fprintf(infop->dthi_out, ");\n") < 0)
437                 return (dt_set_errno(dtp, errno));
438
439         if (fprintf(infop->dthi_out,
440             "#ifndef\t__sparc\n"
441             "extern int __dtraceenabled_%s___%s(void);\n"
442             "#else\n"
443             "extern int __dtraceenabled_%s___%s(long);\n"
444             "#endif\n",
445             infop->dthi_pfname, fname, infop->dthi_pfname, fname) < 0)
446                 return (dt_set_errno(dtp, errno));
447
448         return (0);
449 }
450
451 /*ARGSUSED*/
452 static int
453 dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
454 {
455         dt_header_info_t *infop = data;
456         dtrace_hdl_t *dtp = infop->dthi_dtp;
457         dt_probe_t *prp = idp->di_data;
458         char *mname, *fname;
459         const char *p;
460         int i;
461
462         p = prp->pr_name;
463         for (i = 0; (p = strchr(p, '-')) != NULL; i++)
464                 p++;
465
466         mname = alloca(strlen(prp->pr_name) + 1);
467         dt_header_fmt_macro(mname, prp->pr_name);
468
469         fname = alloca(strlen(prp->pr_name) + 1 + i);
470         dt_header_fmt_func(fname, prp->pr_name);
471
472         if (fprintf(infop->dthi_out, "#define\t%s_%s(",
473             infop->dthi_pmname, mname) < 0)
474                 return (dt_set_errno(dtp, errno));
475
476         for (i = 0; i < prp->pr_nargc; i++) {
477                 if (fprintf(infop->dthi_out, "arg%d", i) < 0)
478                         return (dt_set_errno(dtp, errno));
479
480                 if (i + 1 != prp->pr_nargc &&
481                     fprintf(infop->dthi_out, ", ") < 0)
482                         return (dt_set_errno(dtp, errno));
483         }
484
485         if (!infop->dthi_empty) {
486                 if (fprintf(infop->dthi_out, ") \\\n\t") < 0)
487                         return (dt_set_errno(dtp, errno));
488
489                 if (fprintf(infop->dthi_out, "__dtrace_%s___%s(",
490                     infop->dthi_pfname, fname) < 0)
491                         return (dt_set_errno(dtp, errno));
492
493                 for (i = 0; i < prp->pr_nargc; i++) {
494                         if (fprintf(infop->dthi_out, "arg%d", i) < 0)
495                                 return (dt_set_errno(dtp, errno));
496
497                         if (i + 1 != prp->pr_nargc &&
498                             fprintf(infop->dthi_out, ", ") < 0)
499                                 return (dt_set_errno(dtp, errno));
500                 }
501         }
502
503         if (fprintf(infop->dthi_out, ")\n") < 0)
504                 return (dt_set_errno(dtp, errno));
505
506         if (!infop->dthi_empty) {
507                 if (fprintf(infop->dthi_out,
508                     "#ifndef\t__sparc\n"
509                     "#define\t%s_%s_ENABLED() \\\n"
510                     "\t__dtraceenabled_%s___%s()\n"
511                     "#else\n"
512                     "#define\t%s_%s_ENABLED() \\\n"
513                     "\t__dtraceenabled_%s___%s(0)\n"
514                     "#endif\n",
515                     infop->dthi_pmname, mname,
516                     infop->dthi_pfname, fname,
517                     infop->dthi_pmname, mname,
518                     infop->dthi_pfname, fname) < 0)
519                         return (dt_set_errno(dtp, errno));
520
521         } else {
522                 if (fprintf(infop->dthi_out, "#define\t%s_%s_ENABLED() (0)\n",
523                     infop->dthi_pmname, mname) < 0)
524                         return (dt_set_errno(dtp, errno));
525         }
526
527         return (0);
528 }
529
530 static int
531 dt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out)
532 {
533         dt_header_info_t info;
534         const char *p;
535         int i;
536
537         if (pvp->pv_flags & DT_PROVIDER_IMPL)
538                 return (0);
539
540         /*
541          * Count the instances of the '-' character since we'll need to double
542          * those up.
543          */
544         p = pvp->pv_desc.dtvd_name;
545         for (i = 0; (p = strchr(p, '-')) != NULL; i++)
546                 p++;
547
548         info.dthi_dtp = dtp;
549         info.dthi_out = out;
550         info.dthi_empty = 0;
551
552         info.dthi_pmname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1);
553         dt_header_fmt_macro(info.dthi_pmname, pvp->pv_desc.dtvd_name);
554
555         info.dthi_pfname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1 + i);
556         dt_header_fmt_func(info.dthi_pfname, pvp->pv_desc.dtvd_name);
557
558         if (fprintf(out, "#if _DTRACE_VERSION\n\n") < 0)
559                 return (dt_set_errno(dtp, errno));
560
561         if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
562                 return (-1); /* dt_errno is set for us */
563         if (fprintf(out, "\n\n") < 0)
564                 return (dt_set_errno(dtp, errno));
565         if (dt_idhash_iter(pvp->pv_probes, dt_header_decl, &info) != 0)
566                 return (-1); /* dt_errno is set for us */
567
568         if (fprintf(out, "\n#else\n\n") < 0)
569                 return (dt_set_errno(dtp, errno));
570
571         info.dthi_empty = 1;
572
573         if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
574                 return (-1); /* dt_errno is set for us */
575
576         if (fprintf(out, "\n#endif\n\n") < 0)
577                 return (dt_set_errno(dtp, errno));
578
579         return (0);
580 }
581
582 int
583 dtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname)
584 {
585         dt_provider_t *pvp;
586         char *mfname, *p;
587
588         if (fname != NULL) {
589                 if ((p = strrchr(fname, '/')) != NULL)
590                         fname = p + 1;
591
592                 mfname = alloca(strlen(fname) + 1);
593                 dt_header_fmt_macro(mfname, fname);
594                 if (fprintf(out, "#ifndef\t_%s\n#define\t_%s\n\n",
595                     mfname, mfname) < 0)
596                         return (dt_set_errno(dtp, errno));
597         }
598
599         if (fprintf(out, "#include <unistd.h>\n\n") < 0)
600                 return (-1);
601
602         if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0)
603                 return (-1);
604
605         for (pvp = dt_list_next(&dtp->dt_provlist);
606             pvp != NULL; pvp = dt_list_next(pvp)) {
607                 if (dt_header_provider(dtp, pvp, out) != 0)
608                         return (-1); /* dt_errno is set for us */
609         }
610
611         if (fprintf(out, "\n#ifdef\t__cplusplus\n}\n#endif\n") < 0)
612                 return (dt_set_errno(dtp, errno));
613
614         if (fname != NULL && fprintf(out, "\n#endif\t/* _%s */\n", mfname) < 0)
615                 return (dt_set_errno(dtp, errno));
616
617         return (0);
618 }