Index: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c =================================================================== --- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c (revision 274636) +++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c (revision 274637) @@ -1,986 +1,986 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011 by Delphix. All rights reserved. * Copyright (c) 2013, Joyent, Inc. All rights reserved. */ #include #if defined(sun) #include #endif #include #if defined(sun) #include #endif #include #include #include #include #include #include #include #include #include #include void dt_dof_init(dtrace_hdl_t *dtp) { dt_dof_t *ddo = &dtp->dt_dof; ddo->ddo_hdl = dtp; ddo->ddo_nsecs = 0; ddo->ddo_strsec = DOF_SECIDX_NONE; ddo->ddo_xlimport = NULL; ddo->ddo_xlexport = NULL; dt_buf_create(dtp, &ddo->ddo_secs, "section headers", 0); dt_buf_create(dtp, &ddo->ddo_strs, "string table", 0); dt_buf_create(dtp, &ddo->ddo_ldata, "loadable data", 0); dt_buf_create(dtp, &ddo->ddo_udata, "unloadable data", 0); dt_buf_create(dtp, &ddo->ddo_probes, "probe data", 0); dt_buf_create(dtp, &ddo->ddo_args, "probe args", 0); dt_buf_create(dtp, &ddo->ddo_offs, "probe offs", 0); dt_buf_create(dtp, &ddo->ddo_enoffs, "probe is-enabled offs", 0); dt_buf_create(dtp, &ddo->ddo_rels, "probe rels", 0); dt_buf_create(dtp, &ddo->ddo_xlms, "xlate members", 0); } void dt_dof_fini(dtrace_hdl_t *dtp) { dt_dof_t *ddo = &dtp->dt_dof; dt_free(dtp, ddo->ddo_xlimport); dt_free(dtp, ddo->ddo_xlexport); dt_buf_destroy(dtp, &ddo->ddo_secs); dt_buf_destroy(dtp, &ddo->ddo_strs); dt_buf_destroy(dtp, &ddo->ddo_ldata); dt_buf_destroy(dtp, &ddo->ddo_udata); dt_buf_destroy(dtp, &ddo->ddo_probes); dt_buf_destroy(dtp, &ddo->ddo_args); dt_buf_destroy(dtp, &ddo->ddo_offs); dt_buf_destroy(dtp, &ddo->ddo_enoffs); dt_buf_destroy(dtp, &ddo->ddo_rels); dt_buf_destroy(dtp, &ddo->ddo_xlms); } static int dt_dof_reset(dtrace_hdl_t *dtp, dtrace_prog_t *pgp) { dt_dof_t *ddo = &dtp->dt_dof; uint_t i, nx = dtp->dt_xlatorid; assert(ddo->ddo_hdl == dtp); ddo->ddo_pgp = pgp; ddo->ddo_nsecs = 0; ddo->ddo_strsec = DOF_SECIDX_NONE; dt_free(dtp, ddo->ddo_xlimport); dt_free(dtp, ddo->ddo_xlexport); ddo->ddo_xlimport = dt_alloc(dtp, sizeof (dof_secidx_t) * nx); ddo->ddo_xlexport = dt_alloc(dtp, sizeof (dof_secidx_t) * nx); if (nx != 0 && (ddo->ddo_xlimport == NULL || ddo->ddo_xlexport == NULL)) return (-1); /* errno is set for us */ for (i = 0; i < nx; i++) { ddo->ddo_xlimport[i] = DOF_SECIDX_NONE; ddo->ddo_xlexport[i] = DOF_SECIDX_NONE; } dt_buf_reset(dtp, &ddo->ddo_secs); dt_buf_reset(dtp, &ddo->ddo_strs); dt_buf_reset(dtp, &ddo->ddo_ldata); dt_buf_reset(dtp, &ddo->ddo_udata); dt_buf_reset(dtp, &ddo->ddo_probes); dt_buf_reset(dtp, &ddo->ddo_args); dt_buf_reset(dtp, &ddo->ddo_offs); dt_buf_reset(dtp, &ddo->ddo_enoffs); dt_buf_reset(dtp, &ddo->ddo_rels); dt_buf_reset(dtp, &ddo->ddo_xlms); return (0); } /* * Add a loadable DOF section to the file using the specified data buffer and * the specified DOF section attributes. DOF_SECF_LOAD must be set in flags. * If 'data' is NULL, the caller is responsible for manipulating the ldata buf. */ static dof_secidx_t dof_add_lsect(dt_dof_t *ddo, const void *data, uint32_t type, uint32_t align, uint32_t flags, uint32_t entsize, uint64_t size) { dtrace_hdl_t *dtp = ddo->ddo_hdl; dof_sec_t s; s.dofs_type = type; s.dofs_align = align; s.dofs_flags = flags | DOF_SECF_LOAD; s.dofs_entsize = entsize; s.dofs_offset = dt_buf_offset(&ddo->ddo_ldata, align); s.dofs_size = size; dt_buf_write(dtp, &ddo->ddo_secs, &s, sizeof (s), sizeof (uint64_t)); if (data != NULL) dt_buf_write(dtp, &ddo->ddo_ldata, data, size, align); return (ddo->ddo_nsecs++); } /* * Add an unloadable DOF section to the file using the specified data buffer * and DOF section attributes. DOF_SECF_LOAD must *not* be set in flags. * If 'data' is NULL, the caller is responsible for manipulating the udata buf. */ static dof_secidx_t dof_add_usect(dt_dof_t *ddo, const void *data, uint32_t type, uint32_t align, uint32_t flags, uint32_t entsize, uint64_t size) { dtrace_hdl_t *dtp = ddo->ddo_hdl; dof_sec_t s; s.dofs_type = type; s.dofs_align = align; s.dofs_flags = flags & ~DOF_SECF_LOAD; s.dofs_entsize = entsize; s.dofs_offset = dt_buf_offset(&ddo->ddo_udata, align); s.dofs_size = size; dt_buf_write(dtp, &ddo->ddo_secs, &s, sizeof (s), sizeof (uint64_t)); if (data != NULL) dt_buf_write(dtp, &ddo->ddo_udata, data, size, align); return (ddo->ddo_nsecs++); } /* * Add a string to the global string table associated with the DOF. The offset * of the string is returned as an index into the string table. */ static dof_stridx_t dof_add_string(dt_dof_t *ddo, const char *s) { dt_buf_t *bp = &ddo->ddo_strs; dof_stridx_t i = dt_buf_len(bp); if (i != 0 && (s == NULL || *s == '\0')) return (0); /* string table has \0 at offset 0 */ dt_buf_write(ddo->ddo_hdl, bp, s, strlen(s) + 1, sizeof (char)); return (i); } static dof_attr_t dof_attr(const dtrace_attribute_t *ap) { return (DOF_ATTR(ap->dtat_name, ap->dtat_data, ap->dtat_class)); } static dof_secidx_t dof_add_difo(dt_dof_t *ddo, const dtrace_difo_t *dp) { dof_secidx_t dsecs[5]; /* enough for all possible DIFO sections */ uint_t nsecs = 0; dof_difohdr_t *dofd; dof_relohdr_t dofr; dof_secidx_t relsec; dof_secidx_t strsec = DOF_SECIDX_NONE; dof_secidx_t intsec = DOF_SECIDX_NONE; dof_secidx_t hdrsec = DOF_SECIDX_NONE; if (dp->dtdo_buf != NULL) { dsecs[nsecs++] = dof_add_lsect(ddo, dp->dtdo_buf, DOF_SECT_DIF, sizeof (dif_instr_t), 0, sizeof (dif_instr_t), sizeof (dif_instr_t) * dp->dtdo_len); } if (dp->dtdo_inttab != NULL) { dsecs[nsecs++] = intsec = dof_add_lsect(ddo, dp->dtdo_inttab, DOF_SECT_INTTAB, sizeof (uint64_t), 0, sizeof (uint64_t), sizeof (uint64_t) * dp->dtdo_intlen); } if (dp->dtdo_strtab != NULL) { dsecs[nsecs++] = strsec = dof_add_lsect(ddo, dp->dtdo_strtab, DOF_SECT_STRTAB, sizeof (char), 0, 0, dp->dtdo_strlen); } if (dp->dtdo_vartab != NULL) { dsecs[nsecs++] = dof_add_lsect(ddo, dp->dtdo_vartab, DOF_SECT_VARTAB, sizeof (uint_t), 0, sizeof (dtrace_difv_t), sizeof (dtrace_difv_t) * dp->dtdo_varlen); } if (dp->dtdo_xlmtab != NULL) { dof_xlref_t *xlt, *xlp; dt_node_t **pnp; xlt = alloca(sizeof (dof_xlref_t) * dp->dtdo_xlmlen); pnp = dp->dtdo_xlmtab; /* * dtdo_xlmtab contains pointers to the translator members. * The translator itself is in sect ddo_xlimport[dxp->dx_id]. * The XLMEMBERS entries are in order by their dn_membid, so * the member section offset is the population count of bits * in ddo_pgp->dp_xlrefs[] up to and not including dn_membid. */ for (xlp = xlt; xlp < xlt + dp->dtdo_xlmlen; xlp++) { dt_node_t *dnp = *pnp++; dt_xlator_t *dxp = dnp->dn_membexpr->dn_xlator; xlp->dofxr_xlator = ddo->ddo_xlimport[dxp->dx_id]; xlp->dofxr_member = dt_popcb( ddo->ddo_pgp->dp_xrefs[dxp->dx_id], dnp->dn_membid); xlp->dofxr_argn = (uint32_t)dxp->dx_arg; } dsecs[nsecs++] = dof_add_lsect(ddo, xlt, DOF_SECT_XLTAB, sizeof (dof_secidx_t), 0, sizeof (dof_xlref_t), sizeof (dof_xlref_t) * dp->dtdo_xlmlen); } /* * Copy the return type and the array of section indices that form the * DIFO into a single dof_difohdr_t and then add DOF_SECT_DIFOHDR. */ assert(nsecs <= sizeof (dsecs) / sizeof (dsecs[0])); dofd = alloca(sizeof (dtrace_diftype_t) + sizeof (dsecs)); bcopy(&dp->dtdo_rtype, &dofd->dofd_rtype, sizeof (dtrace_diftype_t)); bcopy(dsecs, &dofd->dofd_links, sizeof (dof_secidx_t) * nsecs); hdrsec = dof_add_lsect(ddo, dofd, DOF_SECT_DIFOHDR, sizeof (dof_secidx_t), 0, 0, sizeof (dtrace_diftype_t) + sizeof (dof_secidx_t) * nsecs); /* * Add any other sections related to dtrace_difo_t. These are not * referenced in dof_difohdr_t because they are not used by emulation. */ if (dp->dtdo_kreltab != NULL) { relsec = dof_add_lsect(ddo, dp->dtdo_kreltab, DOF_SECT_RELTAB, sizeof (uint64_t), 0, sizeof (dof_relodesc_t), sizeof (dof_relodesc_t) * dp->dtdo_krelen); /* * This code assumes the target of all relocations is the * integer table 'intsec' (DOF_SECT_INTTAB). If other sections * need relocation in the future this will need to change. */ dofr.dofr_strtab = strsec; dofr.dofr_relsec = relsec; dofr.dofr_tgtsec = intsec; (void) dof_add_lsect(ddo, &dofr, DOF_SECT_KRELHDR, sizeof (dof_secidx_t), 0, 0, sizeof (dof_relohdr_t)); } if (dp->dtdo_ureltab != NULL) { relsec = dof_add_lsect(ddo, dp->dtdo_ureltab, DOF_SECT_RELTAB, sizeof (uint64_t), 0, sizeof (dof_relodesc_t), sizeof (dof_relodesc_t) * dp->dtdo_urelen); /* * This code assumes the target of all relocations is the * integer table 'intsec' (DOF_SECT_INTTAB). If other sections * need relocation in the future this will need to change. */ dofr.dofr_strtab = strsec; dofr.dofr_relsec = relsec; dofr.dofr_tgtsec = intsec; (void) dof_add_lsect(ddo, &dofr, DOF_SECT_URELHDR, sizeof (dof_secidx_t), 0, 0, sizeof (dof_relohdr_t)); } return (hdrsec); } static void dof_add_translator(dt_dof_t *ddo, const dt_xlator_t *dxp, uint_t type) { dtrace_hdl_t *dtp = ddo->ddo_hdl; dof_xlmember_t dofxm; dof_xlator_t dofxl; dof_secidx_t *xst; char buf[DT_TYPE_NAMELEN]; dt_node_t *dnp; uint_t i = 0; assert(type == DOF_SECT_XLIMPORT || type == DOF_SECT_XLEXPORT); xst = type == DOF_SECT_XLIMPORT ? ddo->ddo_xlimport : ddo->ddo_xlexport; if (xst[dxp->dx_id] != DOF_SECIDX_NONE) return; /* translator has already been emitted */ dt_buf_reset(dtp, &ddo->ddo_xlms); /* * Generate an array of dof_xlmember_t's into ddo_xlms. If we are * importing the translator, add only those members referenced by the * program and set the dofxm_difo reference of each member to NONE. If * we're exporting the translator, add all members and a DIFO for each. */ for (dnp = dxp->dx_members; dnp != NULL; dnp = dnp->dn_list, i++) { if (type == DOF_SECT_XLIMPORT) { if (!BT_TEST(ddo->ddo_pgp->dp_xrefs[dxp->dx_id], i)) continue; /* member is not referenced */ dofxm.dofxm_difo = DOF_SECIDX_NONE; } else { dofxm.dofxm_difo = dof_add_difo(ddo, dxp->dx_membdif[dnp->dn_membid]); } dofxm.dofxm_name = dof_add_string(ddo, dnp->dn_membname); dt_node_diftype(dtp, dnp, &dofxm.dofxm_type); dt_buf_write(dtp, &ddo->ddo_xlms, &dofxm, sizeof (dofxm), sizeof (uint32_t)); } dofxl.dofxl_members = dof_add_lsect(ddo, NULL, DOF_SECT_XLMEMBERS, sizeof (uint32_t), 0, sizeof (dofxm), dt_buf_len(&ddo->ddo_xlms)); dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_xlms, sizeof (uint32_t)); dofxl.dofxl_strtab = ddo->ddo_strsec; dofxl.dofxl_argv = dof_add_string(ddo, ctf_type_name( dxp->dx_src_ctfp, dxp->dx_src_type, buf, sizeof (buf))); dofxl.dofxl_argc = 1; dofxl.dofxl_type = dof_add_string(ddo, ctf_type_name( dxp->dx_dst_ctfp, dxp->dx_dst_type, buf, sizeof (buf))); dofxl.dofxl_attr = dof_attr(&dxp->dx_souid.di_attr); xst[dxp->dx_id] = dof_add_lsect(ddo, &dofxl, type, sizeof (uint32_t), 0, 0, sizeof (dofxl)); } /*ARGSUSED*/ static int dof_add_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data) { dt_dof_t *ddo = data; dtrace_hdl_t *dtp = ddo->ddo_hdl; dt_probe_t *prp = idp->di_data; dof_probe_t dofpr; dof_relodesc_t dofr; dt_probe_instance_t *pip; dt_node_t *dnp; char buf[DT_TYPE_NAMELEN]; uint_t i; dofpr.dofpr_addr = 0; dofpr.dofpr_name = dof_add_string(ddo, prp->pr_name); dofpr.dofpr_nargv = dt_buf_len(&ddo->ddo_strs); for (dnp = prp->pr_nargs; dnp != NULL; dnp = dnp->dn_list) { (void) dof_add_string(ddo, ctf_type_name(dnp->dn_ctfp, dnp->dn_type, buf, sizeof (buf))); } dofpr.dofpr_xargv = dt_buf_len(&ddo->ddo_strs); for (dnp = prp->pr_xargs; dnp != NULL; dnp = dnp->dn_list) { (void) dof_add_string(ddo, ctf_type_name(dnp->dn_ctfp, dnp->dn_type, buf, sizeof (buf))); } dofpr.dofpr_argidx = dt_buf_len(&ddo->ddo_args) / sizeof (uint8_t); for (i = 0; i < prp->pr_xargc; i++) { dt_buf_write(dtp, &ddo->ddo_args, &prp->pr_mapping[i], sizeof (uint8_t), sizeof (uint8_t)); } dofpr.dofpr_nargc = prp->pr_nargc; dofpr.dofpr_xargc = prp->pr_xargc; dofpr.dofpr_pad1 = 0; dofpr.dofpr_pad2 = 0; for (pip = prp->pr_inst; pip != NULL; pip = pip->pi_next) { dt_dprintf("adding probe for %s:%s\n", pip->pi_fname, prp->pr_name); dofpr.dofpr_func = dof_add_string(ddo, pip->pi_fname); /* * There should be one probe offset or is-enabled probe offset * or else this probe instance won't have been created. The * kernel will reject DOF which has a probe with no offsets. */ assert(pip->pi_noffs + pip->pi_nenoffs > 0); dofpr.dofpr_offidx = dt_buf_len(&ddo->ddo_offs) / sizeof (uint32_t); dofpr.dofpr_noffs = pip->pi_noffs; dt_buf_write(dtp, &ddo->ddo_offs, pip->pi_offs, pip->pi_noffs * sizeof (uint32_t), sizeof (uint32_t)); dofpr.dofpr_enoffidx = dt_buf_len(&ddo->ddo_enoffs) / sizeof (uint32_t); dofpr.dofpr_nenoffs = pip->pi_nenoffs; dt_buf_write(dtp, &ddo->ddo_enoffs, pip->pi_enoffs, pip->pi_nenoffs * sizeof (uint32_t), sizeof (uint32_t)); /* * If pi_rname isn't set, the relocation will be against the * function name. If it is, the relocation will be against * pi_rname. This will be used if the function is scoped * locally so an alternate symbol is added for the purpose * of this relocation. */ - if (pip->pi_rname[0] == '\0') + if (pip->pi_rname == NULL) dofr.dofr_name = dofpr.dofpr_func; else dofr.dofr_name = dof_add_string(ddo, pip->pi_rname); dofr.dofr_type = DOF_RELO_SETX; dofr.dofr_offset = dt_buf_len(&ddo->ddo_probes); dofr.dofr_data = 0; dt_buf_write(dtp, &ddo->ddo_rels, &dofr, sizeof (dofr), sizeof (uint64_t)); dt_buf_write(dtp, &ddo->ddo_probes, &dofpr, sizeof (dofpr), sizeof (uint64_t)); } return (0); } static int dof_add_provider(dt_dof_t *ddo, const dt_provider_t *pvp) { dtrace_hdl_t *dtp = ddo->ddo_hdl; dof_provider_t dofpv; dof_relohdr_t dofr; dof_secidx_t *dofs; ulong_t xr, nxr; size_t sz; id_t i; if (pvp->pv_flags & DT_PROVIDER_IMPL) { /* * ignore providers that are exported by dtrace(7D) */ return (0); } nxr = dt_popcb(pvp->pv_xrefs, pvp->pv_xrmax); dofs = alloca(sizeof (dof_secidx_t) * (nxr + 1)); xr = 1; /* reserve dofs[0] for the provider itself */ /* * For each translator referenced by the provider (pv_xrefs), emit an * exported translator section for it if one hasn't been created yet. */ for (i = 0; i < pvp->pv_xrmax; i++) { if (BT_TEST(pvp->pv_xrefs, i) && dtp->dt_xlatemode == DT_XL_DYNAMIC) { dof_add_translator(ddo, dt_xlator_lookup_id(dtp, i), DOF_SECT_XLEXPORT); dofs[xr++] = ddo->ddo_xlexport[i]; } } dt_buf_reset(dtp, &ddo->ddo_probes); dt_buf_reset(dtp, &ddo->ddo_args); dt_buf_reset(dtp, &ddo->ddo_offs); dt_buf_reset(dtp, &ddo->ddo_enoffs); dt_buf_reset(dtp, &ddo->ddo_rels); (void) dt_idhash_iter(pvp->pv_probes, dof_add_probe, ddo); if (dt_buf_len(&ddo->ddo_probes) == 0) return (dt_set_errno(dtp, EDT_NOPROBES)); dofpv.dofpv_probes = dof_add_lsect(ddo, NULL, DOF_SECT_PROBES, sizeof (uint64_t), 0, sizeof (dof_probe_t), dt_buf_len(&ddo->ddo_probes)); dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_probes, sizeof (uint64_t)); dofpv.dofpv_prargs = dof_add_lsect(ddo, NULL, DOF_SECT_PRARGS, sizeof (uint8_t), 0, sizeof (uint8_t), dt_buf_len(&ddo->ddo_args)); dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_args, sizeof (uint8_t)); dofpv.dofpv_proffs = dof_add_lsect(ddo, NULL, DOF_SECT_PROFFS, sizeof (uint_t), 0, sizeof (uint_t), dt_buf_len(&ddo->ddo_offs)); dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_offs, sizeof (uint_t)); if ((sz = dt_buf_len(&ddo->ddo_enoffs)) != 0) { dofpv.dofpv_prenoffs = dof_add_lsect(ddo, NULL, DOF_SECT_PRENOFFS, sizeof (uint_t), 0, sizeof (uint_t), sz); } else { dofpv.dofpv_prenoffs = DOF_SECT_NONE; } dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_enoffs, sizeof (uint_t)); dofpv.dofpv_strtab = ddo->ddo_strsec; dofpv.dofpv_name = dof_add_string(ddo, pvp->pv_desc.dtvd_name); dofpv.dofpv_provattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_provider); dofpv.dofpv_modattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_mod); dofpv.dofpv_funcattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_func); dofpv.dofpv_nameattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_name); dofpv.dofpv_argsattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_args); dofs[0] = dof_add_lsect(ddo, &dofpv, DOF_SECT_PROVIDER, sizeof (dof_secidx_t), 0, 0, sizeof (dof_provider_t)); dofr.dofr_strtab = dofpv.dofpv_strtab; dofr.dofr_tgtsec = dofpv.dofpv_probes; dofr.dofr_relsec = dof_add_lsect(ddo, NULL, DOF_SECT_RELTAB, sizeof (uint64_t), 0, sizeof (dof_relodesc_t), dt_buf_len(&ddo->ddo_rels)); dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_rels, sizeof (uint64_t)); (void) dof_add_lsect(ddo, &dofr, DOF_SECT_URELHDR, sizeof (dof_secidx_t), 0, 0, sizeof (dof_relohdr_t)); if (nxr != 0 && dtp->dt_xlatemode == DT_XL_DYNAMIC) { (void) dof_add_lsect(ddo, dofs, DOF_SECT_PREXPORT, sizeof (dof_secidx_t), 0, sizeof (dof_secidx_t), sizeof (dof_secidx_t) * (nxr + 1)); } return (0); } static int dof_hdr(dtrace_hdl_t *dtp, uint8_t dofversion, dof_hdr_t *hp) { /* * If our config values cannot fit in a uint8_t, we can't generate a * DOF header since the values won't fit. This can only happen if the * user forcibly compiles a program with an artificial configuration. */ if (dtp->dt_conf.dtc_difversion > UINT8_MAX || dtp->dt_conf.dtc_difintregs > UINT8_MAX || dtp->dt_conf.dtc_diftupregs > UINT8_MAX) return (dt_set_errno(dtp, EOVERFLOW)); bzero(hp, sizeof (dof_hdr_t)); hp->dofh_ident[DOF_ID_MAG0] = DOF_MAG_MAG0; hp->dofh_ident[DOF_ID_MAG1] = DOF_MAG_MAG1; hp->dofh_ident[DOF_ID_MAG2] = DOF_MAG_MAG2; hp->dofh_ident[DOF_ID_MAG3] = DOF_MAG_MAG3; if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64) hp->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_LP64; else hp->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_ILP32; hp->dofh_ident[DOF_ID_ENCODING] = DOF_ENCODE_NATIVE; hp->dofh_ident[DOF_ID_VERSION] = dofversion; hp->dofh_ident[DOF_ID_DIFVERS] = dtp->dt_conf.dtc_difversion; hp->dofh_ident[DOF_ID_DIFIREG] = dtp->dt_conf.dtc_difintregs; hp->dofh_ident[DOF_ID_DIFTREG] = dtp->dt_conf.dtc_diftupregs; hp->dofh_hdrsize = sizeof (dof_hdr_t); hp->dofh_secsize = sizeof (dof_sec_t); hp->dofh_secoff = sizeof (dof_hdr_t); return (0); } void * dtrace_dof_create(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t flags) { dt_dof_t *ddo = &dtp->dt_dof; const dtrace_ecbdesc_t *edp, *last; const dtrace_probedesc_t *pdp; const dtrace_actdesc_t *ap; const dt_stmt_t *stp; uint_t maxacts = 0; uint_t maxfmt = 0; dt_provider_t *pvp; dt_xlator_t *dxp; dof_actdesc_t *dofa; dof_sec_t *sp; size_t ssize, lsize; dof_hdr_t h; dt_buf_t dof; char *fmt; uint_t i; if (flags & ~DTRACE_D_MASK) { (void) dt_set_errno(dtp, EINVAL); return (NULL); } flags |= dtp->dt_dflags; if (dof_hdr(dtp, pgp->dp_dofversion, &h) != 0) return (NULL); if (dt_dof_reset(dtp, pgp) != 0) return (NULL); /* * Iterate through the statement list computing the maximum number of * actions and the maximum format string for allocating local buffers. */ for (last = NULL, stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = dt_list_next(stp), last = edp) { dtrace_stmtdesc_t *sdp = stp->ds_desc; dtrace_actdesc_t *ap = sdp->dtsd_action; if (sdp->dtsd_fmtdata != NULL) { i = dtrace_printf_format(dtp, sdp->dtsd_fmtdata, NULL, 0); maxfmt = MAX(maxfmt, i); } if ((edp = sdp->dtsd_ecbdesc) == last) continue; /* same ecb as previous statement */ for (i = 0, ap = edp->dted_action; ap; ap = ap->dtad_next) i++; maxacts = MAX(maxacts, i); } dofa = alloca(sizeof (dof_actdesc_t) * maxacts); fmt = alloca(maxfmt + 1); ddo->ddo_strsec = dof_add_lsect(ddo, NULL, DOF_SECT_STRTAB, 1, 0, 0, 0); (void) dof_add_string(ddo, ""); /* * If there are references to dynamic translators in the program, add * an imported translator table entry for each referenced translator. */ if (pgp->dp_xrefslen != 0) { for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL; dxp = dt_list_next(dxp)) { if (dxp->dx_id < pgp->dp_xrefslen && pgp->dp_xrefs[dxp->dx_id] != NULL) dof_add_translator(ddo, dxp, DOF_SECT_XLIMPORT); } } /* * Now iterate through the statement list, creating the DOF section * headers and data for each one and adding them to our buffers. */ for (last = NULL, stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = dt_list_next(stp), last = edp) { dof_secidx_t probesec = DOF_SECIDX_NONE; dof_secidx_t prdsec = DOF_SECIDX_NONE; dof_secidx_t actsec = DOF_SECIDX_NONE; const dt_stmt_t *next = stp; dtrace_stmtdesc_t *sdp = stp->ds_desc; dof_stridx_t strndx = 0; dof_probedesc_t dofp; dof_ecbdesc_t dofe; uint_t i; if ((edp = stp->ds_desc->dtsd_ecbdesc) == last) continue; /* same ecb as previous statement */ pdp = &edp->dted_probe; /* * Add a DOF_SECT_PROBEDESC for the ECB's probe description, * and copy the probe description strings into the string table. */ dofp.dofp_strtab = ddo->ddo_strsec; dofp.dofp_provider = dof_add_string(ddo, pdp->dtpd_provider); dofp.dofp_mod = dof_add_string(ddo, pdp->dtpd_mod); dofp.dofp_func = dof_add_string(ddo, pdp->dtpd_func); dofp.dofp_name = dof_add_string(ddo, pdp->dtpd_name); dofp.dofp_id = pdp->dtpd_id; probesec = dof_add_lsect(ddo, &dofp, DOF_SECT_PROBEDESC, sizeof (dof_secidx_t), 0, sizeof (dof_probedesc_t), sizeof (dof_probedesc_t)); /* * If there is a predicate DIFO associated with the ecbdesc, * write out the DIFO sections and save the DIFO section index. */ if (edp->dted_pred.dtpdd_difo != NULL) prdsec = dof_add_difo(ddo, edp->dted_pred.dtpdd_difo); /* * Now iterate through the action list generating DIFOs as * referenced therein and adding action descriptions to 'dofa'. */ for (i = 0, ap = edp->dted_action; ap != NULL; ap = ap->dtad_next, i++) { if (ap->dtad_difo != NULL) { dofa[i].dofa_difo = dof_add_difo(ddo, ap->dtad_difo); } else dofa[i].dofa_difo = DOF_SECIDX_NONE; /* * If the first action in a statement has string data, * add the string to the global string table. This can * be due either to a printf() format string * (dtsd_fmtdata) or a print() type string * (dtsd_strdata). */ if (sdp != NULL && ap == sdp->dtsd_action) { if (sdp->dtsd_fmtdata != NULL) { (void) dtrace_printf_format(dtp, sdp->dtsd_fmtdata, fmt, maxfmt + 1); strndx = dof_add_string(ddo, fmt); } else if (sdp->dtsd_strdata != NULL) { strndx = dof_add_string(ddo, sdp->dtsd_strdata); } else { strndx = 0; /* use dtad_arg instead */ } if ((next = dt_list_next(next)) != NULL) sdp = next->ds_desc; else sdp = NULL; } if (strndx != 0) { dofa[i].dofa_arg = strndx; dofa[i].dofa_strtab = ddo->ddo_strsec; } else { dofa[i].dofa_arg = ap->dtad_arg; dofa[i].dofa_strtab = DOF_SECIDX_NONE; } dofa[i].dofa_kind = ap->dtad_kind; dofa[i].dofa_ntuple = ap->dtad_ntuple; dofa[i].dofa_uarg = ap->dtad_uarg; } if (i > 0) { actsec = dof_add_lsect(ddo, dofa, DOF_SECT_ACTDESC, sizeof (uint64_t), 0, sizeof (dof_actdesc_t), sizeof (dof_actdesc_t) * i); } /* * Now finally, add the DOF_SECT_ECBDESC referencing all the * previously created sub-sections. */ dofe.dofe_probes = probesec; dofe.dofe_pred = prdsec; dofe.dofe_actions = actsec; dofe.dofe_pad = 0; dofe.dofe_uarg = edp->dted_uarg; (void) dof_add_lsect(ddo, &dofe, DOF_SECT_ECBDESC, sizeof (uint64_t), 0, 0, sizeof (dof_ecbdesc_t)); } /* * If any providers are user-defined, output DOF sections corresponding * to the providers and the probes and arguments that they define. */ if (flags & DTRACE_D_PROBES) { for (pvp = dt_list_next(&dtp->dt_provlist); pvp != NULL; pvp = dt_list_next(pvp)) { if (dof_add_provider(ddo, pvp) != 0) return (NULL); } } /* * If we're not stripping unloadable sections, generate compiler * comments and any other unloadable miscellany. */ if (!(flags & DTRACE_D_STRIP)) { (void) dof_add_usect(ddo, _dtrace_version, DOF_SECT_COMMENTS, sizeof (char), 0, 0, strlen(_dtrace_version) + 1); (void) dof_add_usect(ddo, &dtp->dt_uts, DOF_SECT_UTSNAME, sizeof (char), 0, 0, sizeof (struct utsname)); } /* * Compute and fill in the appropriate values for the dof_hdr_t's * dofh_secnum, dofh_loadsz, and dofh_filez values. */ h.dofh_secnum = ddo->ddo_nsecs; ssize = sizeof (h) + dt_buf_len(&ddo->ddo_secs); h.dofh_loadsz = ssize + dt_buf_len(&ddo->ddo_ldata) + dt_buf_len(&ddo->ddo_strs); if (dt_buf_len(&ddo->ddo_udata) != 0) { lsize = roundup(h.dofh_loadsz, sizeof (uint64_t)); h.dofh_filesz = lsize + dt_buf_len(&ddo->ddo_udata); } else { lsize = h.dofh_loadsz; h.dofh_filesz = lsize; } /* * Set the global DOF_SECT_STRTAB's offset to be after the header, * section headers, and other loadable data. Since we're going to * iterate over the buffer data directly, we must check for errors. */ if ((i = dt_buf_error(&ddo->ddo_secs)) != 0) { (void) dt_set_errno(dtp, i); return (NULL); } sp = dt_buf_ptr(&ddo->ddo_secs); assert(sp[ddo->ddo_strsec].dofs_type == DOF_SECT_STRTAB); assert(ssize == sizeof (h) + sizeof (dof_sec_t) * ddo->ddo_nsecs); sp[ddo->ddo_strsec].dofs_offset = ssize + dt_buf_len(&ddo->ddo_ldata); sp[ddo->ddo_strsec].dofs_size = dt_buf_len(&ddo->ddo_strs); /* * Now relocate all the other section headers by adding the appropriate * delta to their respective dofs_offset values. */ for (i = 0; i < ddo->ddo_nsecs; i++, sp++) { if (i == ddo->ddo_strsec) continue; /* already relocated above */ if (sp->dofs_flags & DOF_SECF_LOAD) sp->dofs_offset += ssize; else sp->dofs_offset += lsize; } /* * Finally, assemble the complete in-memory DOF buffer by writing the * header and then concatenating all our buffers. dt_buf_concat() will * propagate any errors and cause dt_buf_claim() to return NULL. */ dt_buf_create(dtp, &dof, "dof", h.dofh_filesz); dt_buf_write(dtp, &dof, &h, sizeof (h), sizeof (uint64_t)); dt_buf_concat(dtp, &dof, &ddo->ddo_secs, sizeof (uint64_t)); dt_buf_concat(dtp, &dof, &ddo->ddo_ldata, sizeof (uint64_t)); dt_buf_concat(dtp, &dof, &ddo->ddo_strs, sizeof (char)); dt_buf_concat(dtp, &dof, &ddo->ddo_udata, sizeof (uint64_t)); return (dt_buf_claim(dtp, &dof)); } void dtrace_dof_destroy(dtrace_hdl_t *dtp, void *dof) { dt_free(dtp, dof); } void * dtrace_getopt_dof(dtrace_hdl_t *dtp) { dof_hdr_t *dof; dof_sec_t *sec; dof_optdesc_t *dofo; int i, nopts = 0, len = sizeof (dof_hdr_t) + roundup(sizeof (dof_sec_t), sizeof (uint64_t)); for (i = 0; i < DTRACEOPT_MAX; i++) { if (dtp->dt_options[i] != DTRACEOPT_UNSET) nopts++; } len += sizeof (dof_optdesc_t) * nopts; if ((dof = dt_zalloc(dtp, len)) == NULL || dof_hdr(dtp, DOF_VERSION, dof) != 0) { dt_free(dtp, dof); return (NULL); } dof->dofh_secnum = 1; /* only DOF_SECT_OPTDESC */ dof->dofh_loadsz = len; dof->dofh_filesz = len; /* * Fill in the option section header... */ sec = (dof_sec_t *)((uintptr_t)dof + sizeof (dof_hdr_t)); sec->dofs_type = DOF_SECT_OPTDESC; sec->dofs_align = sizeof (uint64_t); sec->dofs_flags = DOF_SECF_LOAD; sec->dofs_entsize = sizeof (dof_optdesc_t); dofo = (dof_optdesc_t *)((uintptr_t)sec + roundup(sizeof (dof_sec_t), sizeof (uint64_t))); sec->dofs_offset = (uintptr_t)dofo - (uintptr_t)dof; sec->dofs_size = sizeof (dof_optdesc_t) * nopts; for (i = 0; i < DTRACEOPT_MAX; i++) { if (dtp->dt_options[i] == DTRACEOPT_UNSET) continue; dofo->dofo_option = i; dofo->dofo_strtab = DOF_SECIDX_NONE; dofo->dofo_value = dtp->dt_options[i]; dofo++; } return (dof); } void * dtrace_geterr_dof(dtrace_hdl_t *dtp) { if (dtp->dt_errprog != NULL) return (dtrace_dof_create(dtp, dtp->dt_errprog, 0)); (void) dt_set_errno(dtp, EDT_BADERROR); return (NULL); } Index: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c =================================================================== --- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c (revision 274636) +++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c (revision 274637) @@ -1,902 +1,901 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2013, Joyent, Inc. All rights reserved. */ #include #if defined(sun) #include #endif #include #include #include #include #if defined(sun) #include #endif #include #include #include #include #include #include #include #include static dt_provider_t * dt_provider_insert(dtrace_hdl_t *dtp, dt_provider_t *pvp, uint_t h) { dt_list_append(&dtp->dt_provlist, pvp); pvp->pv_next = dtp->dt_provs[h]; dtp->dt_provs[h] = pvp; dtp->dt_nprovs++; return (pvp); } dt_provider_t * dt_provider_lookup(dtrace_hdl_t *dtp, const char *name) { uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_provbuckets; dtrace_providerdesc_t desc; dt_provider_t *pvp; for (pvp = dtp->dt_provs[h]; pvp != NULL; pvp = pvp->pv_next) { if (strcmp(pvp->pv_desc.dtvd_name, name) == 0) return (pvp); } if (strisglob(name) || name[0] == '\0') { (void) dt_set_errno(dtp, EDT_NOPROV); return (NULL); } bzero(&desc, sizeof (desc)); (void) strlcpy(desc.dtvd_name, name, DTRACE_PROVNAMELEN); if (dt_ioctl(dtp, DTRACEIOC_PROVIDER, &desc) == -1) { (void) dt_set_errno(dtp, errno == ESRCH ? EDT_NOPROV : errno); return (NULL); } if ((pvp = dt_provider_create(dtp, name)) == NULL) return (NULL); /* dt_errno is set for us */ bcopy(&desc, &pvp->pv_desc, sizeof (desc)); pvp->pv_flags |= DT_PROVIDER_IMPL; return (pvp); } dt_provider_t * dt_provider_create(dtrace_hdl_t *dtp, const char *name) { dt_provider_t *pvp; if ((pvp = dt_zalloc(dtp, sizeof (dt_provider_t))) == NULL) return (NULL); (void) strlcpy(pvp->pv_desc.dtvd_name, name, DTRACE_PROVNAMELEN); pvp->pv_probes = dt_idhash_create(pvp->pv_desc.dtvd_name, NULL, 0, 0); pvp->pv_gen = dtp->dt_gen; pvp->pv_hdl = dtp; if (pvp->pv_probes == NULL) { dt_free(dtp, pvp); (void) dt_set_errno(dtp, EDT_NOMEM); return (NULL); } pvp->pv_desc.dtvd_attr.dtpa_provider = _dtrace_prvattr; pvp->pv_desc.dtvd_attr.dtpa_mod = _dtrace_prvattr; pvp->pv_desc.dtvd_attr.dtpa_func = _dtrace_prvattr; pvp->pv_desc.dtvd_attr.dtpa_name = _dtrace_prvattr; pvp->pv_desc.dtvd_attr.dtpa_args = _dtrace_prvattr; return (dt_provider_insert(dtp, pvp, dt_strtab_hash(name, NULL) % dtp->dt_provbuckets)); } void dt_provider_destroy(dtrace_hdl_t *dtp, dt_provider_t *pvp) { dt_provider_t **pp; uint_t h; assert(pvp->pv_hdl == dtp); h = dt_strtab_hash(pvp->pv_desc.dtvd_name, NULL) % dtp->dt_provbuckets; pp = &dtp->dt_provs[h]; while (*pp != NULL && *pp != pvp) pp = &(*pp)->pv_next; assert(*pp != NULL && *pp == pvp); *pp = pvp->pv_next; dt_list_delete(&dtp->dt_provlist, pvp); dtp->dt_nprovs--; if (pvp->pv_probes != NULL) dt_idhash_destroy(pvp->pv_probes); dt_node_link_free(&pvp->pv_nodes); dt_free(dtp, pvp->pv_xrefs); dt_free(dtp, pvp); } int dt_provider_xref(dtrace_hdl_t *dtp, dt_provider_t *pvp, id_t id) { size_t oldsize = BT_SIZEOFMAP(pvp->pv_xrmax); size_t newsize = BT_SIZEOFMAP(dtp->dt_xlatorid); assert(id >= 0 && id < dtp->dt_xlatorid); if (newsize > oldsize) { ulong_t *xrefs = dt_zalloc(dtp, newsize); if (xrefs == NULL) return (-1); bcopy(pvp->pv_xrefs, xrefs, oldsize); dt_free(dtp, pvp->pv_xrefs); pvp->pv_xrefs = xrefs; pvp->pv_xrmax = dtp->dt_xlatorid; } BT_SET(pvp->pv_xrefs, id); return (0); } static uint8_t dt_probe_argmap(dt_node_t *xnp, dt_node_t *nnp) { uint8_t i; for (i = 0; nnp != NULL; i++) { if (nnp->dn_string != NULL && strcmp(nnp->dn_string, xnp->dn_string) == 0) break; else nnp = nnp->dn_list; } return (i); } static dt_node_t * dt_probe_alloc_args(dt_provider_t *pvp, int argc) { dt_node_t *args = NULL, *pnp = NULL, *dnp; int i; for (i = 0; i < argc; i++, pnp = dnp) { if ((dnp = dt_node_xalloc(pvp->pv_hdl, DT_NODE_TYPE)) == NULL) return (NULL); dnp->dn_link = pvp->pv_nodes; pvp->pv_nodes = dnp; if (args == NULL) args = dnp; else pnp->dn_list = dnp; } return (args); } static size_t dt_probe_keylen(const dtrace_probedesc_t *pdp) { return (strlen(pdp->dtpd_mod) + 1 + strlen(pdp->dtpd_func) + 1 + strlen(pdp->dtpd_name) + 1); } static char * dt_probe_key(const dtrace_probedesc_t *pdp, char *s) { (void) snprintf(s, INT_MAX, "%s:%s:%s", pdp->dtpd_mod, pdp->dtpd_func, pdp->dtpd_name); return (s); } /* * If a probe was discovered from the kernel, ask dtrace(7D) for a description * of each of its arguments, including native and translated types. */ static dt_probe_t * dt_probe_discover(dt_provider_t *pvp, const dtrace_probedesc_t *pdp) { dtrace_hdl_t *dtp = pvp->pv_hdl; char *name = dt_probe_key(pdp, alloca(dt_probe_keylen(pdp))); dt_node_t *xargs, *nargs; dt_ident_t *idp; dt_probe_t *prp; dtrace_typeinfo_t dtt; int i, nc, xc; int adc = _dtrace_argmax; dtrace_argdesc_t *adv = alloca(sizeof (dtrace_argdesc_t) * adc); dtrace_argdesc_t *adp = adv; assert(strcmp(pvp->pv_desc.dtvd_name, pdp->dtpd_provider) == 0); assert(pdp->dtpd_id != DTRACE_IDNONE); dt_dprintf("discovering probe %s:%s id=%d\n", pvp->pv_desc.dtvd_name, name, pdp->dtpd_id); for (nc = -1, i = 0; i < adc; i++, adp++) { bzero(adp, sizeof (dtrace_argdesc_t)); adp->dtargd_ndx = i; adp->dtargd_id = pdp->dtpd_id; if (dt_ioctl(dtp, DTRACEIOC_PROBEARG, adp) != 0) { (void) dt_set_errno(dtp, errno); return (NULL); } if (adp->dtargd_ndx == DTRACE_ARGNONE) break; /* all argument descs have been retrieved */ nc = MAX(nc, adp->dtargd_mapping); } xc = i; nc++; /* * The pid provider believes in giving the kernel a break. No reason to * give the kernel all the ctf containers that we're keeping ourselves * just to get it back from it. So if we're coming from a pid provider * probe and the kernel gave us no argument information we'll get some * here. If for some crazy reason the kernel knows about our userland * types then we just ignore this. */ if (xc == 0 && nc == 0 && strncmp(pvp->pv_desc.dtvd_name, "pid", 3) == 0) { nc = adc; dt_pid_get_types(dtp, pdp, adv, &nc); xc = nc; } /* * Now that we have discovered the number of native and translated * arguments from the argument descriptions, allocate a new probe ident * and corresponding dt_probe_t and hash it into the provider. */ xargs = dt_probe_alloc_args(pvp, xc); nargs = dt_probe_alloc_args(pvp, nc); if ((xc != 0 && xargs == NULL) || (nc != 0 && nargs == NULL)) return (NULL); /* dt_errno is set for us */ idp = dt_ident_create(name, DT_IDENT_PROBE, DT_IDFLG_ORPHAN, pdp->dtpd_id, _dtrace_defattr, 0, &dt_idops_probe, NULL, dtp->dt_gen); if (idp == NULL) { (void) dt_set_errno(dtp, EDT_NOMEM); return (NULL); } if ((prp = dt_probe_create(dtp, idp, 2, nargs, nc, xargs, xc)) == NULL) { dt_ident_destroy(idp); return (NULL); } dt_probe_declare(pvp, prp); /* * Once our new dt_probe_t is fully constructed, iterate over the * cached argument descriptions and assign types to prp->pr_nargv[] * and prp->pr_xargv[] and assign mappings to prp->pr_mapping[]. */ for (adp = adv, i = 0; i < xc; i++, adp++) { if (dtrace_type_strcompile(dtp, adp->dtargd_native, &dtt) != 0) { dt_dprintf("failed to resolve input type %s " "for %s:%s arg #%d: %s\n", adp->dtargd_native, pvp->pv_desc.dtvd_name, name, i + 1, dtrace_errmsg(dtp, dtrace_errno(dtp))); dtt.dtt_object = NULL; dtt.dtt_ctfp = NULL; dtt.dtt_type = CTF_ERR; } else { dt_node_type_assign(prp->pr_nargv[adp->dtargd_mapping], dtt.dtt_ctfp, dtt.dtt_type, dtt.dtt_flags & DTT_FL_USER ? B_TRUE : B_FALSE); } if (dtt.dtt_type != CTF_ERR && (adp->dtargd_xlate[0] == '\0' || strcmp(adp->dtargd_native, adp->dtargd_xlate) == 0)) { dt_node_type_propagate(prp->pr_nargv[ adp->dtargd_mapping], prp->pr_xargv[i]); } else if (dtrace_type_strcompile(dtp, adp->dtargd_xlate, &dtt) != 0) { dt_dprintf("failed to resolve output type %s " "for %s:%s arg #%d: %s\n", adp->dtargd_xlate, pvp->pv_desc.dtvd_name, name, i + 1, dtrace_errmsg(dtp, dtrace_errno(dtp))); dtt.dtt_object = NULL; dtt.dtt_ctfp = NULL; dtt.dtt_type = CTF_ERR; } else { dt_node_type_assign(prp->pr_xargv[i], dtt.dtt_ctfp, dtt.dtt_type, B_FALSE); } prp->pr_mapping[i] = adp->dtargd_mapping; prp->pr_argv[i] = dtt; } return (prp); } /* * Lookup a probe declaration based on a known provider and full or partially * specified module, function, and name. If the probe is not known to us yet, * ask dtrace(7D) to match the description and then cache any useful results. */ dt_probe_t * dt_probe_lookup(dt_provider_t *pvp, const char *s) { dtrace_hdl_t *dtp = pvp->pv_hdl; dtrace_probedesc_t pd; dt_ident_t *idp; size_t keylen; char *key; if (dtrace_str2desc(dtp, DTRACE_PROBESPEC_NAME, s, &pd) != 0) return (NULL); /* dt_errno is set for us */ keylen = dt_probe_keylen(&pd); key = dt_probe_key(&pd, alloca(keylen)); /* * If the probe is already declared, then return the dt_probe_t from * the existing identifier. This could come from a static declaration * or it could have been cached from an earlier call to this function. */ if ((idp = dt_idhash_lookup(pvp->pv_probes, key)) != NULL) return (idp->di_data); /* * If the probe isn't known, use the probe description computed above * to ask dtrace(7D) to find the first matching probe. */ if (dt_ioctl(dtp, DTRACEIOC_PROBEMATCH, &pd) == 0) return (dt_probe_discover(pvp, &pd)); if (errno == ESRCH || errno == EBADF) (void) dt_set_errno(dtp, EDT_NOPROBE); else (void) dt_set_errno(dtp, errno); return (NULL); } dt_probe_t * dt_probe_create(dtrace_hdl_t *dtp, dt_ident_t *idp, int protoc, dt_node_t *nargs, uint_t nargc, dt_node_t *xargs, uint_t xargc) { dt_module_t *dmp; dt_probe_t *prp; const char *p; uint_t i; assert(idp->di_kind == DT_IDENT_PROBE); assert(idp->di_data == NULL); /* * If only a single prototype is given, set xargc/s to nargc/s to * simplify subsequent use. Note that we can have one or both of nargs * and xargs be specified but set to NULL, indicating a void prototype. */ if (protoc < 2) { assert(xargs == NULL); assert(xargc == 0); xargs = nargs; xargc = nargc; } if ((prp = dt_alloc(dtp, sizeof (dt_probe_t))) == NULL) return (NULL); prp->pr_pvp = NULL; prp->pr_ident = idp; p = strrchr(idp->di_name, ':'); assert(p != NULL); prp->pr_name = p + 1; prp->pr_nargs = nargs; prp->pr_nargv = dt_alloc(dtp, sizeof (dt_node_t *) * nargc); prp->pr_nargc = nargc; prp->pr_xargs = xargs; prp->pr_xargv = dt_alloc(dtp, sizeof (dt_node_t *) * xargc); prp->pr_xargc = xargc; prp->pr_mapping = dt_alloc(dtp, sizeof (uint8_t) * xargc); prp->pr_inst = NULL; prp->pr_argv = dt_alloc(dtp, sizeof (dtrace_typeinfo_t) * xargc); prp->pr_argc = xargc; if ((prp->pr_nargc != 0 && prp->pr_nargv == NULL) || (prp->pr_xargc != 0 && prp->pr_xargv == NULL) || (prp->pr_xargc != 0 && prp->pr_mapping == NULL) || (prp->pr_argc != 0 && prp->pr_argv == NULL)) { dt_probe_destroy(prp); return (NULL); } for (i = 0; i < xargc; i++, xargs = xargs->dn_list) { if (xargs->dn_string != NULL) prp->pr_mapping[i] = dt_probe_argmap(xargs, nargs); else prp->pr_mapping[i] = i; prp->pr_xargv[i] = xargs; if ((dmp = dt_module_lookup_by_ctf(dtp, xargs->dn_ctfp)) != NULL) prp->pr_argv[i].dtt_object = dmp->dm_name; else prp->pr_argv[i].dtt_object = NULL; prp->pr_argv[i].dtt_ctfp = xargs->dn_ctfp; prp->pr_argv[i].dtt_type = xargs->dn_type; } for (i = 0; i < nargc; i++, nargs = nargs->dn_list) prp->pr_nargv[i] = nargs; idp->di_data = prp; return (prp); } void dt_probe_declare(dt_provider_t *pvp, dt_probe_t *prp) { assert(prp->pr_ident->di_kind == DT_IDENT_PROBE); assert(prp->pr_ident->di_data == prp); assert(prp->pr_pvp == NULL); if (prp->pr_xargs != prp->pr_nargs) pvp->pv_flags &= ~DT_PROVIDER_INTF; prp->pr_pvp = pvp; dt_idhash_xinsert(pvp->pv_probes, prp->pr_ident); } void dt_probe_destroy(dt_probe_t *prp) { dt_probe_instance_t *pip, *pip_next; dtrace_hdl_t *dtp; if (prp->pr_pvp != NULL) dtp = prp->pr_pvp->pv_hdl; else dtp = yypcb->pcb_hdl; dt_node_list_free(&prp->pr_nargs); dt_node_list_free(&prp->pr_xargs); dt_free(dtp, prp->pr_nargv); dt_free(dtp, prp->pr_xargv); for (pip = prp->pr_inst; pip != NULL; pip = pip_next) { pip_next = pip->pi_next; + dt_free(dtp, pip->pi_rname); + dt_free(dtp, pip->pi_fname); dt_free(dtp, pip->pi_offs); dt_free(dtp, pip->pi_enoffs); dt_free(dtp, pip); } dt_free(dtp, prp->pr_mapping); dt_free(dtp, prp->pr_argv); dt_free(dtp, prp); } int dt_probe_define(dt_provider_t *pvp, dt_probe_t *prp, const char *fname, const char *rname, uint32_t offset, int isenabled) { dtrace_hdl_t *dtp = pvp->pv_hdl; dt_probe_instance_t *pip; uint32_t **offs; uint_t *noffs, *maxoffs; assert(fname != NULL); for (pip = prp->pr_inst; pip != NULL; pip = pip->pi_next) { if (strcmp(pip->pi_fname, fname) == 0 && ((rname == NULL && pip->pi_rname[0] == '\0') || (rname != NULL && strcmp(pip->pi_rname, rname)) == 0)) break; } if (pip == NULL) { if ((pip = dt_zalloc(dtp, sizeof (*pip))) == NULL) return (-1); - if ((pip->pi_offs = dt_zalloc(dtp, - sizeof (uint32_t))) == NULL) { - dt_free(dtp, pip); - return (-1); - } + if ((pip->pi_offs = dt_zalloc(dtp, sizeof (uint32_t))) == NULL) + goto nomem; if ((pip->pi_enoffs = dt_zalloc(dtp, - sizeof (uint32_t))) == NULL) { - dt_free(dtp, pip->pi_offs); - dt_free(dtp, pip); - return (-1); - } + sizeof (uint32_t))) == NULL) + goto nomem; - (void) strlcpy(pip->pi_fname, fname, sizeof (pip->pi_fname)); - if (rname != NULL) { - if (strlen(rname) + 1 > sizeof (pip->pi_rname)) { - dt_free(dtp, pip->pi_offs); - dt_free(dtp, pip); - return (dt_set_errno(dtp, EDT_COMPILER)); - } - (void) strcpy(pip->pi_rname, rname); - } + if ((pip->pi_fname = strdup(fname)) == NULL) + goto nomem; + if (rname != NULL && (pip->pi_rname = strdup(rname)) == NULL) + goto nomem; + pip->pi_noffs = 0; pip->pi_maxoffs = 1; pip->pi_nenoffs = 0; pip->pi_maxenoffs = 1; pip->pi_next = prp->pr_inst; prp->pr_inst = pip; } if (isenabled) { offs = &pip->pi_enoffs; noffs = &pip->pi_nenoffs; maxoffs = &pip->pi_maxenoffs; } else { offs = &pip->pi_offs; noffs = &pip->pi_noffs; maxoffs = &pip->pi_maxoffs; } if (*noffs == *maxoffs) { uint_t new_max = *maxoffs * 2; uint32_t *new_offs = dt_alloc(dtp, sizeof (uint32_t) * new_max); if (new_offs == NULL) return (-1); bcopy(*offs, new_offs, sizeof (uint32_t) * *maxoffs); dt_free(dtp, *offs); *maxoffs = new_max; *offs = new_offs; } dt_dprintf("defined probe %s %s:%s %s() +0x%x (%s)\n", isenabled ? "(is-enabled)" : "", pvp->pv_desc.dtvd_name, prp->pr_ident->di_name, fname, offset, rname != NULL ? rname : fname); assert(*noffs < *maxoffs); (*offs)[(*noffs)++] = offset; return (0); + +nomem: + dt_free(dtp, pip->pi_fname); + dt_free(dtp, pip->pi_enoffs); + dt_free(dtp, pip->pi_offs); + dt_free(dtp, pip); + return (dt_set_errno(dtp, EDT_NOMEM)); } /* * Lookup the dynamic translator type tag for the specified probe argument and * assign the type to the specified node. If the type is not yet defined, add * it to the "D" module's type container as a typedef for an unknown type. */ dt_node_t * dt_probe_tag(dt_probe_t *prp, uint_t argn, dt_node_t *dnp) { dtrace_hdl_t *dtp = prp->pr_pvp->pv_hdl; dtrace_typeinfo_t dtt; size_t len; char *tag; len = snprintf(NULL, 0, "__dtrace_%s___%s_arg%u", prp->pr_pvp->pv_desc.dtvd_name, prp->pr_name, argn); tag = alloca(len + 1); (void) snprintf(tag, len + 1, "__dtrace_%s___%s_arg%u", prp->pr_pvp->pv_desc.dtvd_name, prp->pr_name, argn); if (dtrace_lookup_by_type(dtp, DTRACE_OBJ_DDEFS, tag, &dtt) != 0) { dtt.dtt_object = DTRACE_OBJ_DDEFS; dtt.dtt_ctfp = DT_DYN_CTFP(dtp); dtt.dtt_type = ctf_add_typedef(DT_DYN_CTFP(dtp), CTF_ADD_ROOT, tag, DT_DYN_TYPE(dtp)); if (dtt.dtt_type == CTF_ERR || ctf_update(dtt.dtt_ctfp) == CTF_ERR) { xyerror(D_UNKNOWN, "cannot define type %s: %s\n", tag, ctf_errmsg(ctf_errno(dtt.dtt_ctfp))); } } bzero(dnp, sizeof (dt_node_t)); dnp->dn_kind = DT_NODE_TYPE; dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type, B_FALSE); dt_node_attr_assign(dnp, _dtrace_defattr); return (dnp); } /*ARGSUSED*/ static int dt_probe_desc(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, void *arg) { if (((dtrace_probedesc_t *)arg)->dtpd_id == DTRACE_IDNONE) { bcopy(pdp, arg, sizeof (dtrace_probedesc_t)); return (0); } return (1); } dt_probe_t * dt_probe_info(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, dtrace_probeinfo_t *pip) { int m_is_glob = pdp->dtpd_mod[0] == '\0' || strisglob(pdp->dtpd_mod); int f_is_glob = pdp->dtpd_func[0] == '\0' || strisglob(pdp->dtpd_func); int n_is_glob = pdp->dtpd_name[0] == '\0' || strisglob(pdp->dtpd_name); dt_probe_t *prp = NULL; const dtrace_pattr_t *pap; dt_provider_t *pvp; dt_ident_t *idp; /* * Attempt to lookup the probe in our existing cache for this provider. * If none is found and an explicit probe ID was specified, discover * that specific probe and cache its description and arguments. */ if ((pvp = dt_provider_lookup(dtp, pdp->dtpd_provider)) != NULL) { size_t keylen = dt_probe_keylen(pdp); char *key = dt_probe_key(pdp, alloca(keylen)); if ((idp = dt_idhash_lookup(pvp->pv_probes, key)) != NULL) prp = idp->di_data; else if (pdp->dtpd_id != DTRACE_IDNONE) prp = dt_probe_discover(pvp, pdp); } /* * If no probe was found in our cache, convert the caller's partial * probe description into a fully-formed matching probe description by * iterating over up to at most two probes that match 'pdp'. We then * call dt_probe_discover() on the resulting probe identifier. */ if (prp == NULL) { dtrace_probedesc_t pd; int m; bzero(&pd, sizeof (pd)); pd.dtpd_id = DTRACE_IDNONE; /* * Call dtrace_probe_iter() to find matching probes. Our * dt_probe_desc() callback will produce the following results: * * m < 0 dtrace_probe_iter() found zero matches (or failed). * m > 0 dtrace_probe_iter() found more than one match. * m = 0 dtrace_probe_iter() found exactly one match. */ if ((m = dtrace_probe_iter(dtp, pdp, dt_probe_desc, &pd)) < 0) return (NULL); /* dt_errno is set for us */ if ((pvp = dt_provider_lookup(dtp, pd.dtpd_provider)) == NULL) return (NULL); /* dt_errno is set for us */ /* * If more than one probe was matched, then do not report probe * information if either of the following conditions is true: * * (a) The Arguments Data stability of the matched provider is * less than Evolving. * * (b) Any description component that is at least Evolving is * empty or is specified using a globbing expression. * * These conditions imply that providers that provide Evolving * or better Arguments Data stability must guarantee that all * probes with identical field names in a field of Evolving or * better Name stability have identical argument signatures. */ if (m > 0) { if (pvp->pv_desc.dtvd_attr.dtpa_args.dtat_data < DTRACE_STABILITY_EVOLVING) { (void) dt_set_errno(dtp, EDT_UNSTABLE); return (NULL); } if (pvp->pv_desc.dtvd_attr.dtpa_mod.dtat_name >= DTRACE_STABILITY_EVOLVING && m_is_glob) { (void) dt_set_errno(dtp, EDT_UNSTABLE); return (NULL); } if (pvp->pv_desc.dtvd_attr.dtpa_func.dtat_name >= DTRACE_STABILITY_EVOLVING && f_is_glob) { (void) dt_set_errno(dtp, EDT_UNSTABLE); return (NULL); } if (pvp->pv_desc.dtvd_attr.dtpa_name.dtat_name >= DTRACE_STABILITY_EVOLVING && n_is_glob) { (void) dt_set_errno(dtp, EDT_UNSTABLE); return (NULL); } } /* * If we matched a probe exported by dtrace(7D), then discover * the real attributes. Otherwise grab the static declaration. */ if (pd.dtpd_id != DTRACE_IDNONE) prp = dt_probe_discover(pvp, &pd); else prp = dt_probe_lookup(pvp, pd.dtpd_name); if (prp == NULL) return (NULL); /* dt_errno is set for us */ } assert(pvp != NULL && prp != NULL); /* * Compute the probe description attributes by taking the minimum of * the attributes of the specified fields. If no provider is specified * or a glob pattern is used for the provider, use Unstable attributes. */ if (pdp->dtpd_provider[0] == '\0' || strisglob(pdp->dtpd_provider)) pap = &_dtrace_prvdesc; else pap = &pvp->pv_desc.dtvd_attr; pip->dtp_attr = pap->dtpa_provider; if (!m_is_glob) pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_mod); if (!f_is_glob) pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_func); if (!n_is_glob) pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_name); pip->dtp_arga = pap->dtpa_args; pip->dtp_argv = prp->pr_argv; pip->dtp_argc = prp->pr_argc; return (prp); } int dtrace_probe_info(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, dtrace_probeinfo_t *pip) { return (dt_probe_info(dtp, pdp, pip) != NULL ? 0 : -1); } /*ARGSUSED*/ static int dt_probe_iter(dt_idhash_t *ihp, dt_ident_t *idp, dt_probe_iter_t *pit) { const dt_probe_t *prp = idp->di_data; if (!dt_gmatch(prp->pr_name, pit->pit_pat)) return (0); /* continue on and examine next probe in hash */ (void) strlcpy(pit->pit_desc.dtpd_name, prp->pr_name, DTRACE_NAMELEN); pit->pit_desc.dtpd_id = idp->di_id; pit->pit_matches++; return (pit->pit_func(pit->pit_hdl, &pit->pit_desc, pit->pit_arg)); } int dtrace_probe_iter(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, dtrace_probe_f *func, void *arg) { const char *provider = pdp ? pdp->dtpd_provider : NULL; dtrace_id_t id = DTRACE_IDNONE; dtrace_probedesc_t pd; dt_probe_iter_t pit; int cmd, rv; bzero(&pit, sizeof (pit)); pit.pit_hdl = dtp; pit.pit_func = func; pit.pit_arg = arg; pit.pit_pat = pdp ? pdp->dtpd_name : NULL; for (pit.pit_pvp = dt_list_next(&dtp->dt_provlist); pit.pit_pvp != NULL; pit.pit_pvp = dt_list_next(pit.pit_pvp)) { if (pit.pit_pvp->pv_flags & DT_PROVIDER_IMPL) continue; /* we'll get these later using dt_ioctl() */ if (!dt_gmatch(pit.pit_pvp->pv_desc.dtvd_name, provider)) continue; (void) strlcpy(pit.pit_desc.dtpd_provider, pit.pit_pvp->pv_desc.dtvd_name, DTRACE_PROVNAMELEN); if ((rv = dt_idhash_iter(pit.pit_pvp->pv_probes, (dt_idhash_f *)dt_probe_iter, &pit)) != 0) return (rv); } if (pdp != NULL) cmd = DTRACEIOC_PROBEMATCH; else cmd = DTRACEIOC_PROBES; for (;;) { if (pdp != NULL) bcopy(pdp, &pd, sizeof (pd)); pd.dtpd_id = id; if (dt_ioctl(dtp, cmd, &pd) != 0) break; else if ((rv = func(dtp, &pd, arg)) != 0) return (rv); pit.pit_matches++; id = pd.dtpd_id + 1; } switch (errno) { case ESRCH: case EBADF: return (pit.pit_matches ? 0 : dt_set_errno(dtp, EDT_NOPROBE)); case EINVAL: return (dt_set_errno(dtp, EDT_BADPGLOB)); default: return (dt_set_errno(dtp, errno)); } } Index: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.h =================================================================== --- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.h (revision 274636) +++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.h (revision 274637) @@ -1,118 +1,118 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _DT_PROVIDER_H #define _DT_PROVIDER_H #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #ifdef __cplusplus extern "C" { #endif typedef struct dt_provider { dt_list_t pv_list; /* list forward/back pointers */ struct dt_provider *pv_next; /* pointer to next provider in hash */ dtrace_providerdesc_t pv_desc; /* provider name and attributes */ dt_idhash_t *pv_probes; /* probe defs (if user-declared) */ dt_node_t *pv_nodes; /* parse node allocation list */ ulong_t *pv_xrefs; /* translator reference bitmap */ ulong_t pv_xrmax; /* number of valid bits in pv_xrefs */ ulong_t pv_gen; /* generation # that created me */ dtrace_hdl_t *pv_hdl; /* pointer to containing dtrace_hdl */ uint_t pv_flags; /* flags (see below) */ } dt_provider_t; #define DT_PROVIDER_INTF 0x1 /* provider interface declaration */ #define DT_PROVIDER_IMPL 0x2 /* provider implementation is loaded */ typedef struct dt_probe_iter { dtrace_probedesc_t pit_desc; /* description storage */ dtrace_hdl_t *pit_hdl; /* libdtrace handle */ dt_provider_t *pit_pvp; /* current provider */ const char *pit_pat; /* caller's name pattern (or NULL) */ dtrace_probe_f *pit_func; /* caller's function */ void *pit_arg; /* caller's argument */ uint_t pit_matches; /* number of matches */ } dt_probe_iter_t; typedef struct dt_probe_instance { - char pi_fname[DTRACE_FUNCNAMELEN]; /* function name */ - char pi_rname[DTRACE_FUNCNAMELEN + 20]; /* mangled relocation name */ + char *pi_fname; /* function name */ + char *pi_rname; /* mangled relocation name */ uint32_t *pi_offs; /* offsets into the function */ uint32_t *pi_enoffs; /* is-enabled offsets */ uint_t pi_noffs; /* number of offsets */ uint_t pi_maxoffs; /* size of pi_offs allocation */ uint_t pi_nenoffs; /* number of is-enabled offsets */ uint_t pi_maxenoffs; /* size of pi_enoffs allocation */ struct dt_probe_instance *pi_next; /* next instance in the list */ } dt_probe_instance_t; typedef struct dt_probe { dt_provider_t *pr_pvp; /* pointer to containing provider */ dt_ident_t *pr_ident; /* pointer to probe identifier */ const char *pr_name; /* pointer to name component */ dt_node_t *pr_nargs; /* native argument list */ dt_node_t **pr_nargv; /* native argument vector */ uint_t pr_nargc; /* native argument count */ dt_node_t *pr_xargs; /* translated argument list */ dt_node_t **pr_xargv; /* translated argument vector */ uint_t pr_xargc; /* translated argument count */ uint8_t *pr_mapping; /* translated argument mapping */ dt_probe_instance_t *pr_inst; /* list of functions and offsets */ dtrace_typeinfo_t *pr_argv; /* output argument types */ int pr_argc; /* output argument count */ } dt_probe_t; extern dt_provider_t *dt_provider_lookup(dtrace_hdl_t *, const char *); extern dt_provider_t *dt_provider_create(dtrace_hdl_t *, const char *); extern void dt_provider_destroy(dtrace_hdl_t *, dt_provider_t *); extern int dt_provider_xref(dtrace_hdl_t *, dt_provider_t *, id_t); extern dt_probe_t *dt_probe_create(dtrace_hdl_t *, dt_ident_t *, int, dt_node_t *, uint_t, dt_node_t *, uint_t); extern dt_probe_t *dt_probe_info(dtrace_hdl_t *, const dtrace_probedesc_t *, dtrace_probeinfo_t *); extern dt_probe_t *dt_probe_lookup(dt_provider_t *, const char *); extern void dt_probe_declare(dt_provider_t *, dt_probe_t *); extern void dt_probe_destroy(dt_probe_t *); extern int dt_probe_define(dt_provider_t *, dt_probe_t *, const char *, const char *, uint32_t, int); extern dt_node_t *dt_probe_tag(dt_probe_t *, uint_t, dt_node_t *); #ifdef __cplusplus } #endif #endif /* _DT_PROVIDER_H */