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.
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.
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]
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2011 by Delphix. All rights reserved.
36 #include <dt_program.h>
37 #include <dt_printf.h>
38 #include <dt_provider.h>
41 dt_program_create(dtrace_hdl_t
*dtp
)
43 dtrace_prog_t
*pgp
= dt_zalloc(dtp
, sizeof (dtrace_prog_t
));
46 dt_list_append(&dtp
->dt_programs
, pgp
);
48 (void) dt_set_errno(dtp
, EDT_NOMEM
);
53 * By default, programs start with DOF version 1 so that output files
54 * containing DOF are backward compatible. If a program requires new
55 * DOF features, the version is increased as needed.
57 pgp
->dp_dofversion
= DOF_VERSION_1
;
63 dt_program_destroy(dtrace_hdl_t
*dtp
, dtrace_prog_t
*pgp
)
65 dt_stmt_t
*stp
, *next
;
68 for (stp
= dt_list_next(&pgp
->dp_stmts
); stp
!= NULL
; stp
= next
) {
69 next
= dt_list_next(stp
);
70 dtrace_stmt_destroy(dtp
, stp
->ds_desc
);
74 for (i
= 0; i
< pgp
->dp_xrefslen
; i
++)
75 dt_free(dtp
, pgp
->dp_xrefs
[i
]);
77 dt_free(dtp
, pgp
->dp_xrefs
);
78 dt_list_delete(&dtp
->dt_programs
, pgp
);
84 dtrace_program_info(dtrace_hdl_t
*dtp
, dtrace_prog_t
*pgp
,
85 dtrace_proginfo_t
*pip
)
89 dtrace_ecbdesc_t
*last
= NULL
;
94 bzero(pip
, sizeof (dtrace_proginfo_t
));
96 if (dt_list_next(&pgp
->dp_stmts
) != NULL
) {
97 pip
->dpi_descattr
= _dtrace_maxattr
;
98 pip
->dpi_stmtattr
= _dtrace_maxattr
;
100 pip
->dpi_descattr
= _dtrace_defattr
;
101 pip
->dpi_stmtattr
= _dtrace_defattr
;
104 for (stp
= dt_list_next(&pgp
->dp_stmts
); stp
; stp
= dt_list_next(stp
)) {
105 dtrace_ecbdesc_t
*edp
= stp
->ds_desc
->dtsd_ecbdesc
;
112 dt_attr_min(stp
->ds_desc
->dtsd_descattr
, pip
->dpi_descattr
);
115 dt_attr_min(stp
->ds_desc
->dtsd_stmtattr
, pip
->dpi_stmtattr
);
118 * If there aren't any actions, account for the fact that
119 * recording the epid will generate a record.
121 if (edp
->dted_action
== NULL
)
124 for (ap
= edp
->dted_action
; ap
!= NULL
; ap
= ap
->dtad_next
) {
125 if (ap
->dtad_kind
== DTRACEACT_SPECULATE
) {
126 pip
->dpi_speculations
++;
130 if (DTRACEACT_ISAGG(ap
->dtad_kind
)) {
131 pip
->dpi_recgens
-= ap
->dtad_arg
;
132 pip
->dpi_aggregates
++;
136 if (DTRACEACT_ISDESTRUCTIVE(ap
->dtad_kind
))
139 if (ap
->dtad_kind
== DTRACEACT_DIFEXPR
&&
140 ap
->dtad_difo
->dtdo_rtype
.dtdt_kind
==
142 ap
->dtad_difo
->dtdo_rtype
.dtdt_size
== 0)
151 dtrace_program_exec(dtrace_hdl_t
*dtp
, dtrace_prog_t
*pgp
,
152 dtrace_proginfo_t
*pip
)
157 dtrace_program_info(dtp
, pgp
, pip
);
159 if ((dof
= dtrace_dof_create(dtp
, pgp
, DTRACE_D_STRIP
)) == NULL
)
162 n
= dt_ioctl(dtp
, DTRACEIOC_ENABLE
, dof
);
163 dtrace_dof_destroy(dtp
, dof
);
177 err
= EDT_ENABLING_ERR
;
183 return (dt_set_errno(dtp
, err
));
187 pip
->dpi_matches
+= n
;
193 dt_ecbdesc_hold(dtrace_ecbdesc_t
*edp
)
199 dt_ecbdesc_release(dtrace_hdl_t
*dtp
, dtrace_ecbdesc_t
*edp
)
201 if (--edp
->dted_refcnt
> 0)
204 dt_difo_free(dtp
, edp
->dted_pred
.dtpdd_difo
);
205 assert(edp
->dted_action
== NULL
);
210 dt_ecbdesc_create(dtrace_hdl_t
*dtp
, const dtrace_probedesc_t
*pdp
)
212 dtrace_ecbdesc_t
*edp
;
214 if ((edp
= dt_zalloc(dtp
, sizeof (dtrace_ecbdesc_t
))) == NULL
) {
215 (void) dt_set_errno(dtp
, EDT_NOMEM
);
219 edp
->dted_probe
= *pdp
;
220 dt_ecbdesc_hold(edp
);
225 dtrace_stmt_create(dtrace_hdl_t
*dtp
, dtrace_ecbdesc_t
*edp
)
227 dtrace_stmtdesc_t
*sdp
;
229 if ((sdp
= dt_zalloc(dtp
, sizeof (dtrace_stmtdesc_t
))) == NULL
)
232 dt_ecbdesc_hold(edp
);
233 sdp
->dtsd_ecbdesc
= edp
;
234 sdp
->dtsd_descattr
= _dtrace_defattr
;
235 sdp
->dtsd_stmtattr
= _dtrace_defattr
;
241 dtrace_stmt_action(dtrace_hdl_t
*dtp
, dtrace_stmtdesc_t
*sdp
)
243 dtrace_actdesc_t
*new;
244 dtrace_ecbdesc_t
*edp
= sdp
->dtsd_ecbdesc
;
246 if ((new = dt_alloc(dtp
, sizeof (dtrace_actdesc_t
))) == NULL
)
249 if (sdp
->dtsd_action_last
!= NULL
) {
250 assert(sdp
->dtsd_action
!= NULL
);
251 assert(sdp
->dtsd_action_last
->dtad_next
== NULL
);
252 sdp
->dtsd_action_last
->dtad_next
= new;
254 dtrace_actdesc_t
*ap
= edp
->dted_action
;
256 assert(sdp
->dtsd_action
== NULL
);
257 sdp
->dtsd_action
= new;
259 while (ap
!= NULL
&& ap
->dtad_next
!= NULL
)
263 edp
->dted_action
= new;
268 sdp
->dtsd_action_last
= new;
269 bzero(new, sizeof (dtrace_actdesc_t
));
270 new->dtad_uarg
= (uintptr_t)sdp
;
276 dtrace_stmt_add(dtrace_hdl_t
*dtp
, dtrace_prog_t
*pgp
, dtrace_stmtdesc_t
*sdp
)
278 dt_stmt_t
*stp
= dt_alloc(dtp
, sizeof (dt_stmt_t
));
281 return (-1); /* errno is set for us */
283 dt_list_append(&pgp
->dp_stmts
, stp
);
290 dtrace_stmt_iter(dtrace_hdl_t
*dtp
, dtrace_prog_t
*pgp
,
291 dtrace_stmt_f
*func
, void *data
)
293 dt_stmt_t
*stp
, *next
;
296 for (stp
= dt_list_next(&pgp
->dp_stmts
); stp
!= NULL
; stp
= next
) {
297 next
= dt_list_next(stp
);
298 if ((status
= func(dtp
, pgp
, stp
->ds_desc
, data
)) != 0)
306 dtrace_stmt_destroy(dtrace_hdl_t
*dtp
, dtrace_stmtdesc_t
*sdp
)
308 dtrace_ecbdesc_t
*edp
= sdp
->dtsd_ecbdesc
;
311 * We need to remove any actions that we have on this ECB, and
312 * remove our hold on the ECB itself.
314 if (sdp
->dtsd_action
!= NULL
) {
315 dtrace_actdesc_t
*last
= sdp
->dtsd_action_last
;
316 dtrace_actdesc_t
*ap
, *next
;
318 assert(last
!= NULL
);
320 for (ap
= edp
->dted_action
; ap
!= NULL
; ap
= ap
->dtad_next
) {
321 if (ap
== sdp
->dtsd_action
)
324 if (ap
->dtad_next
== sdp
->dtsd_action
)
330 if (ap
== edp
->dted_action
)
331 edp
->dted_action
= last
->dtad_next
;
333 ap
->dtad_next
= last
->dtad_next
;
336 * We have now removed our action list from its ECB; we can
337 * safely destroy the list.
339 last
->dtad_next
= NULL
;
341 for (ap
= sdp
->dtsd_action
; ap
!= NULL
; ap
= next
) {
342 assert(ap
->dtad_uarg
== (uintptr_t)sdp
);
343 dt_difo_free(dtp
, ap
->dtad_difo
);
344 next
= ap
->dtad_next
;
349 if (sdp
->dtsd_fmtdata
!= NULL
)
350 dt_printf_destroy(sdp
->dtsd_fmtdata
);
351 dt_free(dtp
, sdp
->dtsd_strdata
);
353 dt_ecbdesc_release(dtp
, sdp
->dtsd_ecbdesc
);
357 typedef struct dt_header_info
{
358 dtrace_hdl_t
*dthi_dtp
; /* consumer handle */
359 FILE *dthi_out
; /* output file */
360 char *dthi_pmname
; /* provider macro name */
361 char *dthi_pfname
; /* provider function name */
362 int dthi_empty
; /* should we generate empty macros */
366 dt_header_fmt_macro(char *buf
, const char *str
)
370 *buf
++ = *str
++ + 'A' - 'a';
371 } else if (*str
== '-') {
374 } else if (*str
== '.') {
377 } else if ((*buf
++ = *str
++) == '\0') {
384 dt_header_fmt_func(char *buf
, const char *str
)
391 } else if ((*buf
++ = *str
++) == '\0') {
399 dt_header_decl(dt_idhash_t
*dhp
, dt_ident_t
*idp
, void *data
)
401 dt_header_info_t
*infop
= data
;
402 dtrace_hdl_t
*dtp
= infop
->dthi_dtp
;
403 dt_probe_t
*prp
= idp
->di_data
;
405 char buf
[DT_TYPE_NAMELEN
];
411 for (i
= 0; (p
= strchr(p
, '-')) != NULL
; i
++)
414 fname
= alloca(strlen(prp
->pr_name
) + 1 + i
);
415 dt_header_fmt_func(fname
, prp
->pr_name
);
417 if (fprintf(infop
->dthi_out
, "extern void __dtrace_%s___%s(",
418 infop
->dthi_pfname
, fname
) < 0)
419 return (dt_set_errno(dtp
, errno
));
421 for (dnp
= prp
->pr_nargs
, i
= 0; dnp
!= NULL
; dnp
= dnp
->dn_list
, i
++) {
422 if (fprintf(infop
->dthi_out
, "%s",
423 ctf_type_name(dnp
->dn_ctfp
, dnp
->dn_type
,
424 buf
, sizeof (buf
))) < 0)
425 return (dt_set_errno(dtp
, errno
));
427 if (i
+ 1 != prp
->pr_nargc
&&
428 fprintf(infop
->dthi_out
, ", ") < 0)
429 return (dt_set_errno(dtp
, errno
));
432 if (i
== 0 && fprintf(infop
->dthi_out
, "void") < 0)
433 return (dt_set_errno(dtp
, errno
));
435 if (fprintf(infop
->dthi_out
, ");\n") < 0)
436 return (dt_set_errno(dtp
, errno
));
438 if (fprintf(infop
->dthi_out
,
440 "extern int __dtraceenabled_%s___%s(void);\n"
442 "extern int __dtraceenabled_%s___%s(long);\n"
444 infop
->dthi_pfname
, fname
, infop
->dthi_pfname
, fname
) < 0)
445 return (dt_set_errno(dtp
, errno
));
452 dt_header_probe(dt_idhash_t
*dhp
, dt_ident_t
*idp
, void *data
)
454 dt_header_info_t
*infop
= data
;
455 dtrace_hdl_t
*dtp
= infop
->dthi_dtp
;
456 dt_probe_t
*prp
= idp
->di_data
;
462 for (i
= 0; (p
= strchr(p
, '-')) != NULL
; i
++)
465 mname
= alloca(strlen(prp
->pr_name
) + 1);
466 dt_header_fmt_macro(mname
, prp
->pr_name
);
468 fname
= alloca(strlen(prp
->pr_name
) + 1 + i
);
469 dt_header_fmt_func(fname
, prp
->pr_name
);
471 if (fprintf(infop
->dthi_out
, "#define\t%s_%s(",
472 infop
->dthi_pmname
, mname
) < 0)
473 return (dt_set_errno(dtp
, errno
));
475 for (i
= 0; i
< prp
->pr_nargc
; i
++) {
476 if (fprintf(infop
->dthi_out
, "arg%d", i
) < 0)
477 return (dt_set_errno(dtp
, errno
));
479 if (i
+ 1 != prp
->pr_nargc
&&
480 fprintf(infop
->dthi_out
, ", ") < 0)
481 return (dt_set_errno(dtp
, errno
));
484 if (!infop
->dthi_empty
) {
485 if (fprintf(infop
->dthi_out
, ") \\\n\t") < 0)
486 return (dt_set_errno(dtp
, errno
));
488 if (fprintf(infop
->dthi_out
, "__dtrace_%s___%s(",
489 infop
->dthi_pfname
, fname
) < 0)
490 return (dt_set_errno(dtp
, errno
));
492 for (i
= 0; i
< prp
->pr_nargc
; i
++) {
493 if (fprintf(infop
->dthi_out
, "arg%d", i
) < 0)
494 return (dt_set_errno(dtp
, errno
));
496 if (i
+ 1 != prp
->pr_nargc
&&
497 fprintf(infop
->dthi_out
, ", ") < 0)
498 return (dt_set_errno(dtp
, errno
));
502 if (fprintf(infop
->dthi_out
, ")\n") < 0)
503 return (dt_set_errno(dtp
, errno
));
505 if (!infop
->dthi_empty
) {
506 if (fprintf(infop
->dthi_out
,
508 "#define\t%s_%s_ENABLED() \\\n"
509 "\t__dtraceenabled_%s___%s()\n"
511 "#define\t%s_%s_ENABLED() \\\n"
512 "\t__dtraceenabled_%s___%s(0)\n"
514 infop
->dthi_pmname
, mname
,
515 infop
->dthi_pfname
, fname
,
516 infop
->dthi_pmname
, mname
,
517 infop
->dthi_pfname
, fname
) < 0)
518 return (dt_set_errno(dtp
, errno
));
521 if (fprintf(infop
->dthi_out
, "#define\t%s_%s_ENABLED() (0)\n",
522 infop
->dthi_pmname
, mname
) < 0)
523 return (dt_set_errno(dtp
, errno
));
530 dt_header_provider(dtrace_hdl_t
*dtp
, dt_provider_t
*pvp
, FILE *out
)
532 dt_header_info_t info
;
536 if (pvp
->pv_flags
& DT_PROVIDER_IMPL
)
540 * Count the instances of the '-' character since we'll need to double
543 p
= pvp
->pv_desc
.dtvd_name
;
544 for (i
= 0; (p
= strchr(p
, '-')) != NULL
; i
++)
551 info
.dthi_pmname
= alloca(strlen(pvp
->pv_desc
.dtvd_name
) + 1);
552 dt_header_fmt_macro(info
.dthi_pmname
, pvp
->pv_desc
.dtvd_name
);
554 info
.dthi_pfname
= alloca(strlen(pvp
->pv_desc
.dtvd_name
) + 1 + i
);
555 dt_header_fmt_func(info
.dthi_pfname
, pvp
->pv_desc
.dtvd_name
);
557 if (fprintf(out
, "#if _DTRACE_VERSION\n\n") < 0)
558 return (dt_set_errno(dtp
, errno
));
560 if (dt_idhash_iter(pvp
->pv_probes
, dt_header_probe
, &info
) != 0)
561 return (-1); /* dt_errno is set for us */
562 if (fprintf(out
, "\n\n") < 0)
563 return (dt_set_errno(dtp
, errno
));
564 if (dt_idhash_iter(pvp
->pv_probes
, dt_header_decl
, &info
) != 0)
565 return (-1); /* dt_errno is set for us */
567 if (fprintf(out
, "\n#else\n\n") < 0)
568 return (dt_set_errno(dtp
, errno
));
572 if (dt_idhash_iter(pvp
->pv_probes
, dt_header_probe
, &info
) != 0)
573 return (-1); /* dt_errno is set for us */
575 if (fprintf(out
, "\n#endif\n\n") < 0)
576 return (dt_set_errno(dtp
, errno
));
582 dtrace_program_header(dtrace_hdl_t
*dtp
, FILE *out
, const char *fname
)
588 if ((p
= strrchr(fname
, '/')) != NULL
)
591 mfname
= alloca(strlen(fname
) + 1);
592 dt_header_fmt_macro(mfname
, fname
);
593 if (fprintf(out
, "#ifndef\t_%s\n#define\t_%s\n\n",
595 return (dt_set_errno(dtp
, errno
));
598 if (fprintf(out
, "#include <unistd.h>\n\n") < 0)
601 if (fprintf(out
, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0)
604 for (pvp
= dt_list_next(&dtp
->dt_provlist
);
605 pvp
!= NULL
; pvp
= dt_list_next(pvp
)) {
606 if (dt_header_provider(dtp
, pvp
, out
) != 0)
607 return (-1); /* dt_errno is set for us */
610 if (fprintf(out
, "\n#ifdef\t__cplusplus\n}\n#endif\n") < 0)
611 return (dt_set_errno(dtp
, errno
));
613 if (fname
!= NULL
&& fprintf(out
, "\n#endif\t/* _%s */\n", mfname
) < 0)
614 return (dt_set_errno(dtp
, errno
));