diff options
Diffstat (limited to 'usr/src/lib/libdtrace/common/dt_program.c')
-rw-r--r-- | usr/src/lib/libdtrace/common/dt_program.c | 215 |
1 files changed, 214 insertions, 1 deletions
diff --git a/usr/src/lib/libdtrace/common/dt_program.c b/usr/src/lib/libdtrace/common/dt_program.c index c87d86aa8e..e0d3ada107 100644 --- a/usr/src/lib/libdtrace/common/dt_program.c +++ b/usr/src/lib/libdtrace/common/dt_program.c @@ -19,8 +19,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -31,10 +32,13 @@ #include <stdlib.h> #include <errno.h> #include <assert.h> +#include <ctype.h> +#include <alloca.h> #include <dt_impl.h> #include <dt_program.h> #include <dt_printf.h> +#include <dt_provider.h> dtrace_prog_t * dt_program_create(dtrace_hdl_t *dtp) @@ -339,3 +343,212 @@ dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp) dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc); dt_free(dtp, sdp); } + +typedef struct dt_header_info { + dtrace_hdl_t *dthi_dtp; /* consumer handle */ + FILE *dthi_out; /* output file */ + char *dthi_pmname; /* provider macro name */ + char *dthi_pfname; /* provider function name */ +} dt_header_info_t; + + +static void +dt_header_fmt_macro(char *buf, const char *str) +{ + for (;;) { + if (islower(*str)) { + *buf++ = *str++ + 'A' - 'a'; + } else if (*str == '-') { + *buf++ = '_'; + str++; + } else if (*str == '.') { + *buf++ = '_'; + str++; + } else if ((*buf++ = *str++) == '\0') { + break; + } + } +} + +static void +dt_header_fmt_func(char *buf, const char *str) +{ + for (;;) { + if (*str == '-') { + *buf++ = '_'; + *buf++ = '_'; + str++; + } else if ((*buf++ = *str++) == '\0') { + break; + } + } +} + +/*ARGSUSED*/ +static int +dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data) +{ + dt_header_info_t *infop = data; + dtrace_hdl_t *dtp = infop->dthi_dtp; + dt_probe_t *prp = idp->di_data; + dt_node_t *dnp; + char buf[DT_TYPE_NAMELEN]; + char *fname; + const char *p; + int i; + + p = prp->pr_name; + for (i = 0; (p = strchr(p, '-')) != NULL; i++) + p++; + + fname = alloca(strlen(prp->pr_name) + 1 + i); + dt_header_fmt_func(fname, prp->pr_name); + + if (fprintf(infop->dthi_out, "extern void __dtrace_%s___%s(", + infop->dthi_pfname, fname) < 0) + return (dt_set_errno(dtp, errno)); + + for (dnp = prp->pr_nargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) { + if (fprintf(infop->dthi_out, "%s", + ctf_type_name(dnp->dn_ctfp, dnp->dn_type, + buf, sizeof (buf))) < 0) + return (dt_set_errno(dtp, errno)); + + if (i + 1 != prp->pr_nargc && + fprintf(infop->dthi_out, ", ") < 0) + return (dt_set_errno(dtp, errno)); + } + + if (i == 0 && fprintf(infop->dthi_out, "void") < 0) + return (dt_set_errno(dtp, errno)); + + if (fprintf(infop->dthi_out, ");\n") < 0) + return (dt_set_errno(dtp, errno)); + + return (0); +} + +/*ARGSUSED*/ +static int +dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data) +{ + dt_header_info_t *infop = data; + dtrace_hdl_t *dtp = infop->dthi_dtp; + dt_probe_t *prp = idp->di_data; + char *mname, *fname; + const char *p; + int i; + + p = prp->pr_name; + for (i = 0; (p = strchr(p, '-')) != NULL; i++) + p++; + + mname = alloca(strlen(prp->pr_name) + 1); + dt_header_fmt_macro(mname, prp->pr_name); + + fname = alloca(strlen(prp->pr_name) + 1 + i); + dt_header_fmt_func(fname, prp->pr_name); + + if (fprintf(infop->dthi_out, "#define\t%s_%s(", + infop->dthi_pmname, mname) < 0) + return (dt_set_errno(dtp, errno)); + + for (i = 0; i < prp->pr_nargc; i++) { + if (fprintf(infop->dthi_out, "arg%d", i) < 0) + return (dt_set_errno(dtp, errno)); + + if (i + 1 != prp->pr_nargc && + fprintf(infop->dthi_out, ", ") < 0) + return (dt_set_errno(dtp, errno)); + } + + if (fprintf(infop->dthi_out, ") \\\n\t") < 0) + return (dt_set_errno(dtp, errno)); + + if (fprintf(infop->dthi_out, "__dtrace_%s___%s(", + infop->dthi_pfname, fname) < 0) + return (dt_set_errno(dtp, errno)); + + for (i = 0; i < prp->pr_nargc; i++) { + if (fprintf(infop->dthi_out, "arg%d", i) < 0) + return (dt_set_errno(dtp, errno)); + + if (i + 1 != prp->pr_nargc && + fprintf(infop->dthi_out, ", ") < 0) + return (dt_set_errno(dtp, errno)); + } + + if (fprintf(infop->dthi_out, ")\n") < 0) + return (dt_set_errno(dtp, errno)); + + return (0); +} + +static int +dt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out) +{ + dt_header_info_t info; + const char *p; + int i; + + if (pvp->pv_flags & DT_PROVIDER_IMPL) + return (0); + + p = pvp->pv_desc.dtvd_name; + for (i = 0; (p = strchr(p, '-')) != NULL; i++) + p++; + + info.dthi_dtp = dtp; + info.dthi_out = out; + + info.dthi_pmname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1); + dt_header_fmt_macro(info.dthi_pmname, pvp->pv_desc.dtvd_name); + + info.dthi_pfname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1 + i); + dt_header_fmt_func(info.dthi_pfname, pvp->pv_desc.dtvd_name); + + + if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0) + return (-1); /* dt_errno is set for us */ + if (fprintf(out, "\n\n") < 0) + return (dt_set_errno(dtp, errno)); + if (dt_idhash_iter(pvp->pv_probes, dt_header_decl, &info) != 0) + return (-1); /* dt_errno is set for us */ + + return (0); +} + +int +dtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname) +{ + dt_provider_t *pvp; + char *mfname, *p; + + if (fname != NULL) { + if ((p = strrchr(fname, '/')) != NULL) + fname = p + 1; + + mfname = alloca(strlen(fname) + 1); + dt_header_fmt_macro(mfname, fname); + if (fprintf(out, "#ifndef\t_%s\n#define\t_%s\n\n", + mfname, mfname) < 0) + return (dt_set_errno(dtp, errno)); + } + + if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0) + return (-1); + + for (pvp = dt_list_next(&dtp->dt_provlist); + pvp != NULL; pvp = dt_list_next(pvp)) { + if (dt_header_provider(dtp, pvp, out) != 0) + return (-1); /* dt_errno is set for us */ + } + + if (fprintf(out, "\n#ifdef\t__cplusplus\n}\n#endif\n") < 0) + return (dt_set_errno(dtp, errno)); + + if (fname != NULL && fprintf(out, "\n#endif\t/* _%s */\n", mfname) < 0) + return (dt_set_errno(dtp, errno)); + + return (0); +} |