17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5ac448965Sahl * Common Development and Distribution License (the "License"). 6ac448965Sahl * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21900524f3Sahl 227c478bd9Sstevel@tonic-gate /* 23c9a6ea2eSBryan Cantrill * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 24*deef35fdSEric Schrock * Copyright (c) 2011 by Delphix. All rights reserved. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <unistd.h> 287c478bd9Sstevel@tonic-gate #include <strings.h> 297c478bd9Sstevel@tonic-gate #include <stdlib.h> 307c478bd9Sstevel@tonic-gate #include <errno.h> 317c478bd9Sstevel@tonic-gate #include <assert.h> 32900524f3Sahl #include <ctype.h> 33900524f3Sahl #include <alloca.h> 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate #include <dt_impl.h> 361a7c1b72Smws #include <dt_program.h> 377c478bd9Sstevel@tonic-gate #include <dt_printf.h> 38900524f3Sahl #include <dt_provider.h> 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate dtrace_prog_t * 411a7c1b72Smws dt_program_create(dtrace_hdl_t *dtp) 427c478bd9Sstevel@tonic-gate { 431a7c1b72Smws dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t)); 447c478bd9Sstevel@tonic-gate 45c9a6ea2eSBryan Cantrill if (pgp != NULL) { 467c478bd9Sstevel@tonic-gate dt_list_append(&dtp->dt_programs, pgp); 47c9a6ea2eSBryan Cantrill } else { 487c478bd9Sstevel@tonic-gate (void) dt_set_errno(dtp, EDT_NOMEM); 49c9a6ea2eSBryan Cantrill return (NULL); 50c9a6ea2eSBryan Cantrill } 517c478bd9Sstevel@tonic-gate 52ac448965Sahl /* 53ac448965Sahl * By default, programs start with DOF version 1 so that output files 54ac448965Sahl * containing DOF are backward compatible. If a program requires new 55ac448965Sahl * DOF features, the version is increased as needed. 56ac448965Sahl */ 57ac448965Sahl pgp->dp_dofversion = DOF_VERSION_1; 58ac448965Sahl 597c478bd9Sstevel@tonic-gate return (pgp); 607c478bd9Sstevel@tonic-gate } 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate void 631a7c1b72Smws dt_program_destroy(dtrace_hdl_t *dtp, dtrace_prog_t *pgp) 647c478bd9Sstevel@tonic-gate { 657c478bd9Sstevel@tonic-gate dt_stmt_t *stp, *next; 661a7c1b72Smws uint_t i; 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) { 697c478bd9Sstevel@tonic-gate next = dt_list_next(stp); 701a7c1b72Smws dtrace_stmt_destroy(dtp, stp->ds_desc); 711a7c1b72Smws dt_free(dtp, stp); 727c478bd9Sstevel@tonic-gate } 737c478bd9Sstevel@tonic-gate 741a7c1b72Smws for (i = 0; i < pgp->dp_xrefslen; i++) 751a7c1b72Smws dt_free(dtp, pgp->dp_xrefs[i]); 761a7c1b72Smws 771a7c1b72Smws dt_free(dtp, pgp->dp_xrefs); 787c478bd9Sstevel@tonic-gate dt_list_delete(&dtp->dt_programs, pgp); 791a7c1b72Smws dt_free(dtp, pgp); 807c478bd9Sstevel@tonic-gate } 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 837c478bd9Sstevel@tonic-gate void 847c478bd9Sstevel@tonic-gate dtrace_program_info(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, 857c478bd9Sstevel@tonic-gate dtrace_proginfo_t *pip) 867c478bd9Sstevel@tonic-gate { 877c478bd9Sstevel@tonic-gate dt_stmt_t *stp; 887c478bd9Sstevel@tonic-gate dtrace_actdesc_t *ap; 897c478bd9Sstevel@tonic-gate dtrace_ecbdesc_t *last = NULL; 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate if (pip == NULL) 927c478bd9Sstevel@tonic-gate return; 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate bzero(pip, sizeof (dtrace_proginfo_t)); 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate if (dt_list_next(&pgp->dp_stmts) != NULL) { 977c478bd9Sstevel@tonic-gate pip->dpi_descattr = _dtrace_maxattr; 987c478bd9Sstevel@tonic-gate pip->dpi_stmtattr = _dtrace_maxattr; 997c478bd9Sstevel@tonic-gate } else { 1007c478bd9Sstevel@tonic-gate pip->dpi_descattr = _dtrace_defattr; 1017c478bd9Sstevel@tonic-gate pip->dpi_stmtattr = _dtrace_defattr; 1027c478bd9Sstevel@tonic-gate } 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate for (stp = dt_list_next(&pgp->dp_stmts); stp; stp = dt_list_next(stp)) { 1057c478bd9Sstevel@tonic-gate dtrace_ecbdesc_t *edp = stp->ds_desc->dtsd_ecbdesc; 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate if (edp == last) 1087c478bd9Sstevel@tonic-gate continue; 1097c478bd9Sstevel@tonic-gate last = edp; 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate pip->dpi_descattr = 1127c478bd9Sstevel@tonic-gate dt_attr_min(stp->ds_desc->dtsd_descattr, pip->dpi_descattr); 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate pip->dpi_stmtattr = 1157c478bd9Sstevel@tonic-gate dt_attr_min(stp->ds_desc->dtsd_stmtattr, pip->dpi_stmtattr); 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate /* 1187c478bd9Sstevel@tonic-gate * If there aren't any actions, account for the fact that 1197c478bd9Sstevel@tonic-gate * recording the epid will generate a record. 1207c478bd9Sstevel@tonic-gate */ 1217c478bd9Sstevel@tonic-gate if (edp->dted_action == NULL) 1227c478bd9Sstevel@tonic-gate pip->dpi_recgens++; 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) { 1257c478bd9Sstevel@tonic-gate if (ap->dtad_kind == DTRACEACT_SPECULATE) { 1267c478bd9Sstevel@tonic-gate pip->dpi_speculations++; 1277c478bd9Sstevel@tonic-gate continue; 1287c478bd9Sstevel@tonic-gate } 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate if (DTRACEACT_ISAGG(ap->dtad_kind)) { 1317c478bd9Sstevel@tonic-gate pip->dpi_recgens -= ap->dtad_arg; 1327c478bd9Sstevel@tonic-gate pip->dpi_aggregates++; 1337c478bd9Sstevel@tonic-gate continue; 1347c478bd9Sstevel@tonic-gate } 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate if (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind)) 1377c478bd9Sstevel@tonic-gate continue; 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate if (ap->dtad_kind == DTRACEACT_DIFEXPR && 1407c478bd9Sstevel@tonic-gate ap->dtad_difo->dtdo_rtype.dtdt_kind == 1417c478bd9Sstevel@tonic-gate DIF_TYPE_CTF && 1427c478bd9Sstevel@tonic-gate ap->dtad_difo->dtdo_rtype.dtdt_size == 0) 1437c478bd9Sstevel@tonic-gate continue; 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate pip->dpi_recgens++; 1467c478bd9Sstevel@tonic-gate } 1477c478bd9Sstevel@tonic-gate } 1487c478bd9Sstevel@tonic-gate } 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate int 1517c478bd9Sstevel@tonic-gate dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, 1527c478bd9Sstevel@tonic-gate dtrace_proginfo_t *pip) 1537c478bd9Sstevel@tonic-gate { 1547c478bd9Sstevel@tonic-gate void *dof; 1557c478bd9Sstevel@tonic-gate int n, err; 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate dtrace_program_info(dtp, pgp, pip); 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL) 1607c478bd9Sstevel@tonic-gate return (-1); 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate n = dt_ioctl(dtp, DTRACEIOC_ENABLE, dof); 1637c478bd9Sstevel@tonic-gate dtrace_dof_destroy(dtp, dof); 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate if (n == -1) { 1667c478bd9Sstevel@tonic-gate switch (errno) { 1677c478bd9Sstevel@tonic-gate case EINVAL: 1687c478bd9Sstevel@tonic-gate err = EDT_DIFINVAL; 1697c478bd9Sstevel@tonic-gate break; 1707c478bd9Sstevel@tonic-gate case EFAULT: 1717c478bd9Sstevel@tonic-gate err = EDT_DIFFAULT; 1727c478bd9Sstevel@tonic-gate break; 1737c478bd9Sstevel@tonic-gate case E2BIG: 1747c478bd9Sstevel@tonic-gate err = EDT_DIFSIZE; 1757c478bd9Sstevel@tonic-gate break; 176b9e93c10SJonathan Haslam case EBUSY: 177b9e93c10SJonathan Haslam err = EDT_ENABLING_ERR; 178b9e93c10SJonathan Haslam break; 1797c478bd9Sstevel@tonic-gate default: 1807c478bd9Sstevel@tonic-gate err = errno; 1817c478bd9Sstevel@tonic-gate } 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, err)); 1847c478bd9Sstevel@tonic-gate } 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate if (pip != NULL) 1877c478bd9Sstevel@tonic-gate pip->dpi_matches += n; 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate return (0); 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate 1921a7c1b72Smws static void 1931a7c1b72Smws dt_ecbdesc_hold(dtrace_ecbdesc_t *edp) 1947c478bd9Sstevel@tonic-gate { 1957c478bd9Sstevel@tonic-gate edp->dted_refcnt++; 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate void 1991a7c1b72Smws dt_ecbdesc_release(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp) 2007c478bd9Sstevel@tonic-gate { 2017c478bd9Sstevel@tonic-gate if (--edp->dted_refcnt > 0) 2027c478bd9Sstevel@tonic-gate return; 2037c478bd9Sstevel@tonic-gate 2041a7c1b72Smws dt_difo_free(dtp, edp->dted_pred.dtpdd_difo); 2057c478bd9Sstevel@tonic-gate assert(edp->dted_action == NULL); 2061a7c1b72Smws dt_free(dtp, edp); 2077c478bd9Sstevel@tonic-gate } 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate dtrace_ecbdesc_t * 2101a7c1b72Smws dt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp) 2117c478bd9Sstevel@tonic-gate { 2127c478bd9Sstevel@tonic-gate dtrace_ecbdesc_t *edp; 2137c478bd9Sstevel@tonic-gate 2141a7c1b72Smws if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) { 2157c478bd9Sstevel@tonic-gate (void) dt_set_errno(dtp, EDT_NOMEM); 2167c478bd9Sstevel@tonic-gate return (NULL); 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate edp->dted_probe = *pdp; 2201a7c1b72Smws dt_ecbdesc_hold(edp); 2217c478bd9Sstevel@tonic-gate return (edp); 2227c478bd9Sstevel@tonic-gate } 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate dtrace_stmtdesc_t * 2257c478bd9Sstevel@tonic-gate dtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp) 2267c478bd9Sstevel@tonic-gate { 2277c478bd9Sstevel@tonic-gate dtrace_stmtdesc_t *sdp; 2287c478bd9Sstevel@tonic-gate 2291a7c1b72Smws if ((sdp = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL) 2307c478bd9Sstevel@tonic-gate return (NULL); 2317c478bd9Sstevel@tonic-gate 2321a7c1b72Smws dt_ecbdesc_hold(edp); 2337c478bd9Sstevel@tonic-gate sdp->dtsd_ecbdesc = edp; 2347c478bd9Sstevel@tonic-gate sdp->dtsd_descattr = _dtrace_defattr; 2357c478bd9Sstevel@tonic-gate sdp->dtsd_stmtattr = _dtrace_defattr; 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate return (sdp); 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate dtrace_actdesc_t * 2417c478bd9Sstevel@tonic-gate dtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp) 2427c478bd9Sstevel@tonic-gate { 2437c478bd9Sstevel@tonic-gate dtrace_actdesc_t *new; 2447c478bd9Sstevel@tonic-gate dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc; 2457c478bd9Sstevel@tonic-gate 2461a7c1b72Smws if ((new = dt_alloc(dtp, sizeof (dtrace_actdesc_t))) == NULL) 2477c478bd9Sstevel@tonic-gate return (NULL); 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate if (sdp->dtsd_action_last != NULL) { 2507c478bd9Sstevel@tonic-gate assert(sdp->dtsd_action != NULL); 2517c478bd9Sstevel@tonic-gate assert(sdp->dtsd_action_last->dtad_next == NULL); 2527c478bd9Sstevel@tonic-gate sdp->dtsd_action_last->dtad_next = new; 2537c478bd9Sstevel@tonic-gate } else { 2547c478bd9Sstevel@tonic-gate dtrace_actdesc_t *ap = edp->dted_action; 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate assert(sdp->dtsd_action == NULL); 2577c478bd9Sstevel@tonic-gate sdp->dtsd_action = new; 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate while (ap != NULL && ap->dtad_next != NULL) 2607c478bd9Sstevel@tonic-gate ap = ap->dtad_next; 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate if (ap == NULL) 2637c478bd9Sstevel@tonic-gate edp->dted_action = new; 2647c478bd9Sstevel@tonic-gate else 2657c478bd9Sstevel@tonic-gate ap->dtad_next = new; 2667c478bd9Sstevel@tonic-gate } 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate sdp->dtsd_action_last = new; 2697c478bd9Sstevel@tonic-gate bzero(new, sizeof (dtrace_actdesc_t)); 2707c478bd9Sstevel@tonic-gate new->dtad_uarg = (uintptr_t)sdp; 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate return (new); 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate int 2767c478bd9Sstevel@tonic-gate dtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp) 2777c478bd9Sstevel@tonic-gate { 2781a7c1b72Smws dt_stmt_t *stp = dt_alloc(dtp, sizeof (dt_stmt_t)); 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate if (stp == NULL) 2811a7c1b72Smws return (-1); /* errno is set for us */ 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate dt_list_append(&pgp->dp_stmts, stp); 2847c478bd9Sstevel@tonic-gate stp->ds_desc = sdp; 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate return (0); 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate int 2907c478bd9Sstevel@tonic-gate dtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, 2917c478bd9Sstevel@tonic-gate dtrace_stmt_f *func, void *data) 2927c478bd9Sstevel@tonic-gate { 2937c478bd9Sstevel@tonic-gate dt_stmt_t *stp, *next; 2947c478bd9Sstevel@tonic-gate int status = 0; 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) { 2977c478bd9Sstevel@tonic-gate next = dt_list_next(stp); 2987c478bd9Sstevel@tonic-gate if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0) 2997c478bd9Sstevel@tonic-gate break; 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate return (status); 3037c478bd9Sstevel@tonic-gate } 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate void 3061a7c1b72Smws dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp) 3077c478bd9Sstevel@tonic-gate { 3087c478bd9Sstevel@tonic-gate dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc; 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate /* 3117c478bd9Sstevel@tonic-gate * We need to remove any actions that we have on this ECB, and 3127c478bd9Sstevel@tonic-gate * remove our hold on the ECB itself. 3137c478bd9Sstevel@tonic-gate */ 3147c478bd9Sstevel@tonic-gate if (sdp->dtsd_action != NULL) { 3157c478bd9Sstevel@tonic-gate dtrace_actdesc_t *last = sdp->dtsd_action_last; 3167c478bd9Sstevel@tonic-gate dtrace_actdesc_t *ap, *next; 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate assert(last != NULL); 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) { 3217c478bd9Sstevel@tonic-gate if (ap == sdp->dtsd_action) 3227c478bd9Sstevel@tonic-gate break; 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate if (ap->dtad_next == sdp->dtsd_action) 3257c478bd9Sstevel@tonic-gate break; 3267c478bd9Sstevel@tonic-gate } 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate assert(ap != NULL); 3297c478bd9Sstevel@tonic-gate 3301a7c1b72Smws if (ap == edp->dted_action) 3317c478bd9Sstevel@tonic-gate edp->dted_action = last->dtad_next; 3321a7c1b72Smws else 3337c478bd9Sstevel@tonic-gate ap->dtad_next = last->dtad_next; 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate /* 3367c478bd9Sstevel@tonic-gate * We have now removed our action list from its ECB; we can 3377c478bd9Sstevel@tonic-gate * safely destroy the list. 3387c478bd9Sstevel@tonic-gate */ 3397c478bd9Sstevel@tonic-gate last->dtad_next = NULL; 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate for (ap = sdp->dtsd_action; ap != NULL; ap = next) { 3427c478bd9Sstevel@tonic-gate assert(ap->dtad_uarg == (uintptr_t)sdp); 3431a7c1b72Smws dt_difo_free(dtp, ap->dtad_difo); 3447c478bd9Sstevel@tonic-gate next = ap->dtad_next; 3451a7c1b72Smws dt_free(dtp, ap); 3467c478bd9Sstevel@tonic-gate } 3477c478bd9Sstevel@tonic-gate } 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate if (sdp->dtsd_fmtdata != NULL) 3507c478bd9Sstevel@tonic-gate dt_printf_destroy(sdp->dtsd_fmtdata); 351*deef35fdSEric Schrock dt_free(dtp, sdp->dtsd_strdata); 3527c478bd9Sstevel@tonic-gate 3531a7c1b72Smws dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc); 3541a7c1b72Smws dt_free(dtp, sdp); 3557c478bd9Sstevel@tonic-gate } 356900524f3Sahl 357900524f3Sahl typedef struct dt_header_info { 358900524f3Sahl dtrace_hdl_t *dthi_dtp; /* consumer handle */ 359900524f3Sahl FILE *dthi_out; /* output file */ 360900524f3Sahl char *dthi_pmname; /* provider macro name */ 361900524f3Sahl char *dthi_pfname; /* provider function name */ 3622b6e762cSahl int dthi_empty; /* should we generate empty macros */ 363900524f3Sahl } dt_header_info_t; 364900524f3Sahl 365900524f3Sahl static void 366900524f3Sahl dt_header_fmt_macro(char *buf, const char *str) 367900524f3Sahl { 368900524f3Sahl for (;;) { 369900524f3Sahl if (islower(*str)) { 370900524f3Sahl *buf++ = *str++ + 'A' - 'a'; 371900524f3Sahl } else if (*str == '-') { 372900524f3Sahl *buf++ = '_'; 373900524f3Sahl str++; 374900524f3Sahl } else if (*str == '.') { 375900524f3Sahl *buf++ = '_'; 376900524f3Sahl str++; 377900524f3Sahl } else if ((*buf++ = *str++) == '\0') { 378900524f3Sahl break; 379900524f3Sahl } 380900524f3Sahl } 381900524f3Sahl } 382900524f3Sahl 383900524f3Sahl static void 384900524f3Sahl dt_header_fmt_func(char *buf, const char *str) 385900524f3Sahl { 386900524f3Sahl for (;;) { 387900524f3Sahl if (*str == '-') { 388900524f3Sahl *buf++ = '_'; 389900524f3Sahl *buf++ = '_'; 390900524f3Sahl str++; 391900524f3Sahl } else if ((*buf++ = *str++) == '\0') { 392900524f3Sahl break; 393900524f3Sahl } 394900524f3Sahl } 395900524f3Sahl } 396900524f3Sahl 397900524f3Sahl /*ARGSUSED*/ 398900524f3Sahl static int 399900524f3Sahl dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data) 400900524f3Sahl { 401900524f3Sahl dt_header_info_t *infop = data; 402900524f3Sahl dtrace_hdl_t *dtp = infop->dthi_dtp; 403900524f3Sahl dt_probe_t *prp = idp->di_data; 404900524f3Sahl dt_node_t *dnp; 405900524f3Sahl char buf[DT_TYPE_NAMELEN]; 406900524f3Sahl char *fname; 407900524f3Sahl const char *p; 408900524f3Sahl int i; 409900524f3Sahl 410900524f3Sahl p = prp->pr_name; 411900524f3Sahl for (i = 0; (p = strchr(p, '-')) != NULL; i++) 412900524f3Sahl p++; 413900524f3Sahl 414900524f3Sahl fname = alloca(strlen(prp->pr_name) + 1 + i); 415900524f3Sahl dt_header_fmt_func(fname, prp->pr_name); 416900524f3Sahl 417900524f3Sahl if (fprintf(infop->dthi_out, "extern void __dtrace_%s___%s(", 418900524f3Sahl infop->dthi_pfname, fname) < 0) 419900524f3Sahl return (dt_set_errno(dtp, errno)); 420900524f3Sahl 421900524f3Sahl for (dnp = prp->pr_nargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) { 422900524f3Sahl if (fprintf(infop->dthi_out, "%s", 423900524f3Sahl ctf_type_name(dnp->dn_ctfp, dnp->dn_type, 424900524f3Sahl buf, sizeof (buf))) < 0) 425900524f3Sahl return (dt_set_errno(dtp, errno)); 426900524f3Sahl 427900524f3Sahl if (i + 1 != prp->pr_nargc && 428900524f3Sahl fprintf(infop->dthi_out, ", ") < 0) 429900524f3Sahl return (dt_set_errno(dtp, errno)); 430900524f3Sahl } 431900524f3Sahl 432900524f3Sahl if (i == 0 && fprintf(infop->dthi_out, "void") < 0) 433900524f3Sahl return (dt_set_errno(dtp, errno)); 434900524f3Sahl 435900524f3Sahl if (fprintf(infop->dthi_out, ");\n") < 0) 436900524f3Sahl return (dt_set_errno(dtp, errno)); 437900524f3Sahl 4380bac14eaSahl if (fprintf(infop->dthi_out, 4390bac14eaSahl "#ifndef\t__sparc\n" 4400bac14eaSahl "extern int __dtraceenabled_%s___%s(void);\n" 4410bac14eaSahl "#else\n" 4420bac14eaSahl "extern int __dtraceenabled_%s___%s(long);\n" 4430bac14eaSahl "#endif\n", 4440bac14eaSahl infop->dthi_pfname, fname, infop->dthi_pfname, fname) < 0) 445ac448965Sahl return (dt_set_errno(dtp, errno)); 446ac448965Sahl 447900524f3Sahl return (0); 448900524f3Sahl } 449900524f3Sahl 450900524f3Sahl /*ARGSUSED*/ 451900524f3Sahl static int 452900524f3Sahl dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data) 453900524f3Sahl { 454900524f3Sahl dt_header_info_t *infop = data; 455900524f3Sahl dtrace_hdl_t *dtp = infop->dthi_dtp; 456900524f3Sahl dt_probe_t *prp = idp->di_data; 457900524f3Sahl char *mname, *fname; 458900524f3Sahl const char *p; 459900524f3Sahl int i; 460900524f3Sahl 461900524f3Sahl p = prp->pr_name; 462900524f3Sahl for (i = 0; (p = strchr(p, '-')) != NULL; i++) 463900524f3Sahl p++; 464900524f3Sahl 465900524f3Sahl mname = alloca(strlen(prp->pr_name) + 1); 466900524f3Sahl dt_header_fmt_macro(mname, prp->pr_name); 467900524f3Sahl 468900524f3Sahl fname = alloca(strlen(prp->pr_name) + 1 + i); 469900524f3Sahl dt_header_fmt_func(fname, prp->pr_name); 470900524f3Sahl 471900524f3Sahl if (fprintf(infop->dthi_out, "#define\t%s_%s(", 472900524f3Sahl infop->dthi_pmname, mname) < 0) 473900524f3Sahl return (dt_set_errno(dtp, errno)); 474900524f3Sahl 475900524f3Sahl for (i = 0; i < prp->pr_nargc; i++) { 476900524f3Sahl if (fprintf(infop->dthi_out, "arg%d", i) < 0) 477900524f3Sahl return (dt_set_errno(dtp, errno)); 478900524f3Sahl 479900524f3Sahl if (i + 1 != prp->pr_nargc && 480900524f3Sahl fprintf(infop->dthi_out, ", ") < 0) 481900524f3Sahl return (dt_set_errno(dtp, errno)); 482900524f3Sahl } 483900524f3Sahl 4842b6e762cSahl if (!infop->dthi_empty) { 485900524f3Sahl if (fprintf(infop->dthi_out, ") \\\n\t") < 0) 486900524f3Sahl return (dt_set_errno(dtp, errno)); 487900524f3Sahl 488900524f3Sahl if (fprintf(infop->dthi_out, "__dtrace_%s___%s(", 489900524f3Sahl infop->dthi_pfname, fname) < 0) 490900524f3Sahl return (dt_set_errno(dtp, errno)); 491900524f3Sahl 492900524f3Sahl for (i = 0; i < prp->pr_nargc; i++) { 493900524f3Sahl if (fprintf(infop->dthi_out, "arg%d", i) < 0) 494900524f3Sahl return (dt_set_errno(dtp, errno)); 495900524f3Sahl 496900524f3Sahl if (i + 1 != prp->pr_nargc && 497900524f3Sahl fprintf(infop->dthi_out, ", ") < 0) 498900524f3Sahl return (dt_set_errno(dtp, errno)); 499900524f3Sahl } 5002b6e762cSahl } 501900524f3Sahl 502900524f3Sahl if (fprintf(infop->dthi_out, ")\n") < 0) 503900524f3Sahl return (dt_set_errno(dtp, errno)); 504900524f3Sahl 5052b6e762cSahl if (!infop->dthi_empty) { 5060bac14eaSahl if (fprintf(infop->dthi_out, 5070bac14eaSahl "#ifndef\t__sparc\n" 5080bac14eaSahl "#define\t%s_%s_ENABLED() \\\n" 5090bac14eaSahl "\t__dtraceenabled_%s___%s()\n" 5100bac14eaSahl "#else\n" 5110bac14eaSahl "#define\t%s_%s_ENABLED() \\\n" 5120bac14eaSahl "\t__dtraceenabled_%s___%s(0)\n" 5130bac14eaSahl "#endif\n", 5140bac14eaSahl infop->dthi_pmname, mname, 5150bac14eaSahl infop->dthi_pfname, fname, 5160bac14eaSahl infop->dthi_pmname, mname, 517ac448965Sahl infop->dthi_pfname, fname) < 0) 518ac448965Sahl return (dt_set_errno(dtp, errno)); 5190bac14eaSahl 5202b6e762cSahl } else { 5212b6e762cSahl if (fprintf(infop->dthi_out, "#define\t%s_%s_ENABLED() (0)\n", 5222b6e762cSahl infop->dthi_pmname, mname) < 0) 5232b6e762cSahl return (dt_set_errno(dtp, errno)); 5242b6e762cSahl } 525ac448965Sahl 526900524f3Sahl return (0); 527900524f3Sahl } 528900524f3Sahl 529900524f3Sahl static int 530900524f3Sahl dt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out) 531900524f3Sahl { 532900524f3Sahl dt_header_info_t info; 533900524f3Sahl const char *p; 534900524f3Sahl int i; 535900524f3Sahl 536900524f3Sahl if (pvp->pv_flags & DT_PROVIDER_IMPL) 537900524f3Sahl return (0); 538900524f3Sahl 5392b6e762cSahl /* 5402b6e762cSahl * Count the instances of the '-' character since we'll need to double 5412b6e762cSahl * those up. 5422b6e762cSahl */ 543900524f3Sahl p = pvp->pv_desc.dtvd_name; 544900524f3Sahl for (i = 0; (p = strchr(p, '-')) != NULL; i++) 545900524f3Sahl p++; 546900524f3Sahl 547900524f3Sahl info.dthi_dtp = dtp; 548900524f3Sahl info.dthi_out = out; 5492b6e762cSahl info.dthi_empty = 0; 550900524f3Sahl 551900524f3Sahl info.dthi_pmname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1); 552900524f3Sahl dt_header_fmt_macro(info.dthi_pmname, pvp->pv_desc.dtvd_name); 553900524f3Sahl 554900524f3Sahl info.dthi_pfname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1 + i); 555900524f3Sahl dt_header_fmt_func(info.dthi_pfname, pvp->pv_desc.dtvd_name); 556900524f3Sahl 5572b6e762cSahl if (fprintf(out, "#if _DTRACE_VERSION\n\n") < 0) 5582b6e762cSahl return (dt_set_errno(dtp, errno)); 559900524f3Sahl 560900524f3Sahl if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0) 561900524f3Sahl return (-1); /* dt_errno is set for us */ 562900524f3Sahl if (fprintf(out, "\n\n") < 0) 563900524f3Sahl return (dt_set_errno(dtp, errno)); 564900524f3Sahl if (dt_idhash_iter(pvp->pv_probes, dt_header_decl, &info) != 0) 565900524f3Sahl return (-1); /* dt_errno is set for us */ 566900524f3Sahl 5672b6e762cSahl if (fprintf(out, "\n#else\n\n") < 0) 5682b6e762cSahl return (dt_set_errno(dtp, errno)); 5692b6e762cSahl 5702b6e762cSahl info.dthi_empty = 1; 5712b6e762cSahl 5722b6e762cSahl if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0) 5732b6e762cSahl return (-1); /* dt_errno is set for us */ 5742b6e762cSahl 5752b6e762cSahl if (fprintf(out, "\n#endif\n\n") < 0) 5762b6e762cSahl return (dt_set_errno(dtp, errno)); 5772b6e762cSahl 578900524f3Sahl return (0); 579900524f3Sahl } 580900524f3Sahl 581900524f3Sahl int 582900524f3Sahl dtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname) 583900524f3Sahl { 584900524f3Sahl dt_provider_t *pvp; 585900524f3Sahl char *mfname, *p; 586900524f3Sahl 587900524f3Sahl if (fname != NULL) { 588900524f3Sahl if ((p = strrchr(fname, '/')) != NULL) 589900524f3Sahl fname = p + 1; 590900524f3Sahl 591900524f3Sahl mfname = alloca(strlen(fname) + 1); 592900524f3Sahl dt_header_fmt_macro(mfname, fname); 593900524f3Sahl if (fprintf(out, "#ifndef\t_%s\n#define\t_%s\n\n", 594900524f3Sahl mfname, mfname) < 0) 595900524f3Sahl return (dt_set_errno(dtp, errno)); 596900524f3Sahl } 597900524f3Sahl 5982b6e762cSahl if (fprintf(out, "#include <unistd.h>\n\n") < 0) 5992b6e762cSahl return (-1); 6002b6e762cSahl 601900524f3Sahl if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0) 602900524f3Sahl return (-1); 603900524f3Sahl 604900524f3Sahl for (pvp = dt_list_next(&dtp->dt_provlist); 605900524f3Sahl pvp != NULL; pvp = dt_list_next(pvp)) { 606900524f3Sahl if (dt_header_provider(dtp, pvp, out) != 0) 607900524f3Sahl return (-1); /* dt_errno is set for us */ 608900524f3Sahl } 609900524f3Sahl 610900524f3Sahl if (fprintf(out, "\n#ifdef\t__cplusplus\n}\n#endif\n") < 0) 611900524f3Sahl return (dt_set_errno(dtp, errno)); 612900524f3Sahl 613900524f3Sahl if (fname != NULL && fprintf(out, "\n#endif\t/* _%s */\n", mfname) < 0) 614900524f3Sahl return (dt_set_errno(dtp, errno)); 615900524f3Sahl 616900524f3Sahl return (0); 617900524f3Sahl } 618