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