Path: blob/main/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c
39562 views
/*1* CDDL HEADER START2*3* The contents of this file are subject to the terms of the4* Common Development and Distribution License (the "License").5* You may not use this file except in compliance with the License.6*7* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE8* or http://www.opensolaris.org/os/licensing.9* See the License for the specific language governing permissions10* and limitations under the License.11*12* When distributing Covered Code, include this CDDL HEADER in each13* file and include the License file at usr/src/OPENSOLARIS.LICENSE.14* If applicable, add the following below this CDDL HEADER, with the15* fields enclosed by brackets "[]" replaced with your own identifying16* information: Portions Copyright [yyyy] [name of copyright owner]17*18* CDDL HEADER END19*/2021/*22* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.23* Copyright (c) 2011 by Delphix. All rights reserved.24* Copyright (c) 2013, Joyent, Inc. All rights reserved.25*/2627#include <sys/types.h>28#ifdef illumos29#include <sys/sysmacros.h>30#endif3132#include <strings.h>33#ifdef illumos34#include <alloca.h>35#endif36#include <assert.h>37#include <stdlib.h>38#include <errno.h>39#include <limits.h>4041#include <dt_impl.h>42#include <dt_strtab.h>43#include <dt_program.h>44#include <dt_provider.h>45#include <dt_xlator.h>46#include <dt_dof.h>4748void49dt_dof_init(dtrace_hdl_t *dtp)50{51dt_dof_t *ddo = &dtp->dt_dof;5253ddo->ddo_hdl = dtp;54ddo->ddo_nsecs = 0;55ddo->ddo_strsec = DOF_SECIDX_NONE;56ddo->ddo_xlimport = NULL;57ddo->ddo_xlexport = NULL;5859dt_buf_create(dtp, &ddo->ddo_secs, "section headers", 0);60dt_buf_create(dtp, &ddo->ddo_strs, "string table", 0);61dt_buf_create(dtp, &ddo->ddo_ldata, "loadable data", 0);62dt_buf_create(dtp, &ddo->ddo_udata, "unloadable data", 0);6364dt_buf_create(dtp, &ddo->ddo_probes, "probe data", 0);65dt_buf_create(dtp, &ddo->ddo_args, "probe args", 0);66dt_buf_create(dtp, &ddo->ddo_offs, "probe offs", 0);67dt_buf_create(dtp, &ddo->ddo_enoffs, "probe is-enabled offs", 0);68dt_buf_create(dtp, &ddo->ddo_rels, "probe rels", 0);6970dt_buf_create(dtp, &ddo->ddo_xlms, "xlate members", 0);71}7273void74dt_dof_fini(dtrace_hdl_t *dtp)75{76dt_dof_t *ddo = &dtp->dt_dof;7778dt_free(dtp, ddo->ddo_xlimport);79dt_free(dtp, ddo->ddo_xlexport);8081dt_buf_destroy(dtp, &ddo->ddo_secs);82dt_buf_destroy(dtp, &ddo->ddo_strs);83dt_buf_destroy(dtp, &ddo->ddo_ldata);84dt_buf_destroy(dtp, &ddo->ddo_udata);8586dt_buf_destroy(dtp, &ddo->ddo_probes);87dt_buf_destroy(dtp, &ddo->ddo_args);88dt_buf_destroy(dtp, &ddo->ddo_offs);89dt_buf_destroy(dtp, &ddo->ddo_enoffs);90dt_buf_destroy(dtp, &ddo->ddo_rels);9192dt_buf_destroy(dtp, &ddo->ddo_xlms);93}9495static int96dt_dof_reset(dtrace_hdl_t *dtp, dtrace_prog_t *pgp)97{98dt_dof_t *ddo = &dtp->dt_dof;99uint_t i, nx = dtp->dt_xlatorid;100101assert(ddo->ddo_hdl == dtp);102ddo->ddo_pgp = pgp;103104ddo->ddo_nsecs = 0;105ddo->ddo_strsec = DOF_SECIDX_NONE;106107dt_free(dtp, ddo->ddo_xlimport);108dt_free(dtp, ddo->ddo_xlexport);109110ddo->ddo_xlimport = dt_alloc(dtp, sizeof (dof_secidx_t) * nx);111ddo->ddo_xlexport = dt_alloc(dtp, sizeof (dof_secidx_t) * nx);112113if (nx != 0 && (ddo->ddo_xlimport == NULL || ddo->ddo_xlexport == NULL))114return (-1); /* errno is set for us */115116for (i = 0; i < nx; i++) {117ddo->ddo_xlimport[i] = DOF_SECIDX_NONE;118ddo->ddo_xlexport[i] = DOF_SECIDX_NONE;119}120121dt_buf_reset(dtp, &ddo->ddo_secs);122dt_buf_reset(dtp, &ddo->ddo_strs);123dt_buf_reset(dtp, &ddo->ddo_ldata);124dt_buf_reset(dtp, &ddo->ddo_udata);125126dt_buf_reset(dtp, &ddo->ddo_probes);127dt_buf_reset(dtp, &ddo->ddo_args);128dt_buf_reset(dtp, &ddo->ddo_offs);129dt_buf_reset(dtp, &ddo->ddo_enoffs);130dt_buf_reset(dtp, &ddo->ddo_rels);131132dt_buf_reset(dtp, &ddo->ddo_xlms);133return (0);134}135136/*137* Add a loadable DOF section to the file using the specified data buffer and138* the specified DOF section attributes. DOF_SECF_LOAD must be set in flags.139* If 'data' is NULL, the caller is responsible for manipulating the ldata buf.140*/141static dof_secidx_t142dof_add_lsect(dt_dof_t *ddo, const void *data, uint32_t type,143uint32_t align, uint32_t flags, uint32_t entsize, uint64_t size)144{145dtrace_hdl_t *dtp = ddo->ddo_hdl;146dof_sec_t s;147148s.dofs_type = type;149s.dofs_align = align;150s.dofs_flags = flags | DOF_SECF_LOAD;151s.dofs_entsize = entsize;152s.dofs_offset = dt_buf_offset(&ddo->ddo_ldata, align);153s.dofs_size = size;154155dt_buf_write(dtp, &ddo->ddo_secs, &s, sizeof (s), sizeof (uint64_t));156157if (data != NULL)158dt_buf_write(dtp, &ddo->ddo_ldata, data, size, align);159160return (ddo->ddo_nsecs++);161}162163/*164* Add an unloadable DOF section to the file using the specified data buffer165* and DOF section attributes. DOF_SECF_LOAD must *not* be set in flags.166* If 'data' is NULL, the caller is responsible for manipulating the udata buf.167*/168static dof_secidx_t169dof_add_usect(dt_dof_t *ddo, const void *data, uint32_t type,170uint32_t align, uint32_t flags, uint32_t entsize, uint64_t size)171{172dtrace_hdl_t *dtp = ddo->ddo_hdl;173dof_sec_t s;174175s.dofs_type = type;176s.dofs_align = align;177s.dofs_flags = flags & ~DOF_SECF_LOAD;178s.dofs_entsize = entsize;179s.dofs_offset = dt_buf_offset(&ddo->ddo_udata, align);180s.dofs_size = size;181182dt_buf_write(dtp, &ddo->ddo_secs, &s, sizeof (s), sizeof (uint64_t));183184if (data != NULL)185dt_buf_write(dtp, &ddo->ddo_udata, data, size, align);186187return (ddo->ddo_nsecs++);188}189190/*191* Add a string to the global string table associated with the DOF. The offset192* of the string is returned as an index into the string table.193*/194static dof_stridx_t195dof_add_string(dt_dof_t *ddo, const char *s)196{197dt_buf_t *bp = &ddo->ddo_strs;198dof_stridx_t i = dt_buf_len(bp);199200if (i != 0 && (s == NULL || *s == '\0'))201return (0); /* string table has \0 at offset 0 */202203dt_buf_write(ddo->ddo_hdl, bp, s, strlen(s) + 1, sizeof (char));204return (i);205}206207static dof_attr_t208dof_attr(const dtrace_attribute_t *ap)209{210return (DOF_ATTR(ap->dtat_name, ap->dtat_data, ap->dtat_class));211}212213static dof_secidx_t214dof_add_difo(dt_dof_t *ddo, const dtrace_difo_t *dp)215{216dof_secidx_t dsecs[5]; /* enough for all possible DIFO sections */217uint_t nsecs = 0;218219dof_difohdr_t *dofd;220dof_relohdr_t dofr;221dof_secidx_t relsec;222223dof_secidx_t strsec = DOF_SECIDX_NONE;224dof_secidx_t intsec = DOF_SECIDX_NONE;225dof_secidx_t hdrsec = DOF_SECIDX_NONE;226227if (dp->dtdo_buf != NULL) {228dsecs[nsecs++] = dof_add_lsect(ddo, dp->dtdo_buf,229DOF_SECT_DIF, sizeof (dif_instr_t), 0,230sizeof (dif_instr_t), sizeof (dif_instr_t) * dp->dtdo_len);231}232233if (dp->dtdo_inttab != NULL) {234dsecs[nsecs++] = intsec = dof_add_lsect(ddo, dp->dtdo_inttab,235DOF_SECT_INTTAB, sizeof (uint64_t), 0,236sizeof (uint64_t), sizeof (uint64_t) * dp->dtdo_intlen);237}238239if (dp->dtdo_strtab != NULL) {240dsecs[nsecs++] = strsec = dof_add_lsect(ddo, dp->dtdo_strtab,241DOF_SECT_STRTAB, sizeof (char), 0, 0, dp->dtdo_strlen);242}243244if (dp->dtdo_vartab != NULL) {245dsecs[nsecs++] = dof_add_lsect(ddo, dp->dtdo_vartab,246DOF_SECT_VARTAB, sizeof (uint_t), 0, sizeof (dtrace_difv_t),247sizeof (dtrace_difv_t) * dp->dtdo_varlen);248}249250if (dp->dtdo_xlmtab != NULL) {251dof_xlref_t *xlt, *xlp;252dt_node_t **pnp;253254xlt = alloca(sizeof (dof_xlref_t) * dp->dtdo_xlmlen);255pnp = dp->dtdo_xlmtab;256257/*258* dtdo_xlmtab contains pointers to the translator members.259* The translator itself is in sect ddo_xlimport[dxp->dx_id].260* The XLMEMBERS entries are in order by their dn_membid, so261* the member section offset is the population count of bits262* in ddo_pgp->dp_xlrefs[] up to and not including dn_membid.263*/264for (xlp = xlt; xlp < xlt + dp->dtdo_xlmlen; xlp++) {265dt_node_t *dnp = *pnp++;266dt_xlator_t *dxp = dnp->dn_membexpr->dn_xlator;267268xlp->dofxr_xlator = ddo->ddo_xlimport[dxp->dx_id];269xlp->dofxr_member = dt_popcb(270ddo->ddo_pgp->dp_xrefs[dxp->dx_id], dnp->dn_membid);271xlp->dofxr_argn = (uint32_t)dxp->dx_arg;272}273274dsecs[nsecs++] = dof_add_lsect(ddo, xlt, DOF_SECT_XLTAB,275sizeof (dof_secidx_t), 0, sizeof (dof_xlref_t),276sizeof (dof_xlref_t) * dp->dtdo_xlmlen);277}278279/*280* Copy the return type and the array of section indices that form the281* DIFO into a single dof_difohdr_t and then add DOF_SECT_DIFOHDR.282*/283assert(nsecs <= sizeof (dsecs) / sizeof (dsecs[0]));284dofd = alloca(sizeof (dtrace_diftype_t) + sizeof (dsecs));285bcopy(&dp->dtdo_rtype, &dofd->dofd_rtype, sizeof (dtrace_diftype_t));286bcopy(dsecs, &dofd->dofd_links, sizeof (dof_secidx_t) * nsecs);287288hdrsec = dof_add_lsect(ddo, dofd, DOF_SECT_DIFOHDR,289sizeof (dof_secidx_t), 0, 0,290sizeof (dtrace_diftype_t) + sizeof (dof_secidx_t) * nsecs);291292/*293* Add any other sections related to dtrace_difo_t. These are not294* referenced in dof_difohdr_t because they are not used by emulation.295*/296if (dp->dtdo_kreltab != NULL) {297relsec = dof_add_lsect(ddo, dp->dtdo_kreltab, DOF_SECT_RELTAB,298sizeof (uint64_t), 0, sizeof (dof_relodesc_t),299sizeof (dof_relodesc_t) * dp->dtdo_krelen);300301/*302* This code assumes the target of all relocations is the303* integer table 'intsec' (DOF_SECT_INTTAB). If other sections304* need relocation in the future this will need to change.305*/306dofr.dofr_strtab = strsec;307dofr.dofr_relsec = relsec;308dofr.dofr_tgtsec = intsec;309310(void) dof_add_lsect(ddo, &dofr, DOF_SECT_KRELHDR,311sizeof (dof_secidx_t), 0, 0, sizeof (dof_relohdr_t));312}313314if (dp->dtdo_ureltab != NULL) {315relsec = dof_add_lsect(ddo, dp->dtdo_ureltab, DOF_SECT_RELTAB,316sizeof (uint64_t), 0, sizeof (dof_relodesc_t),317sizeof (dof_relodesc_t) * dp->dtdo_urelen);318319/*320* This code assumes the target of all relocations is the321* integer table 'intsec' (DOF_SECT_INTTAB). If other sections322* need relocation in the future this will need to change.323*/324dofr.dofr_strtab = strsec;325dofr.dofr_relsec = relsec;326dofr.dofr_tgtsec = intsec;327328(void) dof_add_lsect(ddo, &dofr, DOF_SECT_URELHDR,329sizeof (dof_secidx_t), 0, 0, sizeof (dof_relohdr_t));330}331332return (hdrsec);333}334335static void336dof_add_translator(dt_dof_t *ddo, const dt_xlator_t *dxp, uint_t type)337{338dtrace_hdl_t *dtp = ddo->ddo_hdl;339dof_xlmember_t dofxm;340dof_xlator_t dofxl;341dof_secidx_t *xst;342343char buf[DT_TYPE_NAMELEN];344dt_node_t *dnp;345uint_t i = 0;346347assert(type == DOF_SECT_XLIMPORT || type == DOF_SECT_XLEXPORT);348xst = type == DOF_SECT_XLIMPORT ? ddo->ddo_xlimport : ddo->ddo_xlexport;349350if (xst[dxp->dx_id] != DOF_SECIDX_NONE)351return; /* translator has already been emitted */352353dt_buf_reset(dtp, &ddo->ddo_xlms);354355/*356* Generate an array of dof_xlmember_t's into ddo_xlms. If we are357* importing the translator, add only those members referenced by the358* program and set the dofxm_difo reference of each member to NONE. If359* we're exporting the translator, add all members and a DIFO for each.360*/361for (dnp = dxp->dx_members; dnp != NULL; dnp = dnp->dn_list, i++) {362if (type == DOF_SECT_XLIMPORT) {363if (!BT_TEST(ddo->ddo_pgp->dp_xrefs[dxp->dx_id], i))364continue; /* member is not referenced */365dofxm.dofxm_difo = DOF_SECIDX_NONE;366} else {367dofxm.dofxm_difo = dof_add_difo(ddo,368dxp->dx_membdif[dnp->dn_membid]);369}370371dofxm.dofxm_name = dof_add_string(ddo, dnp->dn_membname);372dt_node_diftype(dtp, dnp, &dofxm.dofxm_type);373374dt_buf_write(dtp, &ddo->ddo_xlms,375&dofxm, sizeof (dofxm), sizeof (uint32_t));376}377378dofxl.dofxl_members = dof_add_lsect(ddo, NULL, DOF_SECT_XLMEMBERS,379sizeof (uint32_t), 0, sizeof (dofxm), dt_buf_len(&ddo->ddo_xlms));380381dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_xlms, sizeof (uint32_t));382383dofxl.dofxl_strtab = ddo->ddo_strsec;384dofxl.dofxl_argv = dof_add_string(ddo, ctf_type_name(385dxp->dx_src_ctfp, dxp->dx_src_type, buf, sizeof (buf)));386dofxl.dofxl_argc = 1;387dofxl.dofxl_type = dof_add_string(ddo, ctf_type_name(388dxp->dx_dst_ctfp, dxp->dx_dst_type, buf, sizeof (buf)));389dofxl.dofxl_attr = dof_attr(&dxp->dx_souid.di_attr);390391xst[dxp->dx_id] = dof_add_lsect(ddo, &dofxl, type,392sizeof (uint32_t), 0, 0, sizeof (dofxl));393}394395/*ARGSUSED*/396static int397dof_add_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)398{399dt_dof_t *ddo = data;400dtrace_hdl_t *dtp = ddo->ddo_hdl;401dt_probe_t *prp = idp->di_data;402403dof_probe_t dofpr;404dof_relodesc_t dofr;405dt_probe_instance_t *pip;406dt_node_t *dnp;407408char buf[DT_TYPE_NAMELEN];409uint_t i;410411dofpr.dofpr_addr = 0;412dofpr.dofpr_name = dof_add_string(ddo, prp->pr_name);413dofpr.dofpr_nargv = dt_buf_len(&ddo->ddo_strs);414415for (dnp = prp->pr_nargs; dnp != NULL; dnp = dnp->dn_list) {416(void) dof_add_string(ddo, ctf_type_name(dnp->dn_ctfp,417dnp->dn_type, buf, sizeof (buf)));418}419420dofpr.dofpr_xargv = dt_buf_len(&ddo->ddo_strs);421422for (dnp = prp->pr_xargs; dnp != NULL; dnp = dnp->dn_list) {423(void) dof_add_string(ddo, ctf_type_name(dnp->dn_ctfp,424dnp->dn_type, buf, sizeof (buf)));425}426427dofpr.dofpr_argidx = dt_buf_len(&ddo->ddo_args) / sizeof (uint8_t);428429for (i = 0; i < prp->pr_xargc; i++) {430dt_buf_write(dtp, &ddo->ddo_args, &prp->pr_mapping[i],431sizeof (uint8_t), sizeof (uint8_t));432}433434dofpr.dofpr_nargc = prp->pr_nargc;435dofpr.dofpr_xargc = prp->pr_xargc;436dofpr.dofpr_pad1 = 0;437dofpr.dofpr_pad2 = 0;438439for (pip = prp->pr_inst; pip != NULL; pip = pip->pi_next) {440dt_dprintf("adding probe for %s:%s\n", pip->pi_fname,441prp->pr_name);442443dofpr.dofpr_func = dof_add_string(ddo, pip->pi_fname);444445/*446* There should be one probe offset or is-enabled probe offset447* or else this probe instance won't have been created. The448* kernel will reject DOF which has a probe with no offsets.449*/450assert(pip->pi_noffs + pip->pi_nenoffs > 0);451452dofpr.dofpr_offidx =453dt_buf_len(&ddo->ddo_offs) / sizeof (uint32_t);454dofpr.dofpr_noffs = pip->pi_noffs;455dt_buf_write(dtp, &ddo->ddo_offs, pip->pi_offs,456pip->pi_noffs * sizeof (uint32_t), sizeof (uint32_t));457458dofpr.dofpr_enoffidx =459dt_buf_len(&ddo->ddo_enoffs) / sizeof (uint32_t);460dofpr.dofpr_nenoffs = pip->pi_nenoffs;461dt_buf_write(dtp, &ddo->ddo_enoffs, pip->pi_enoffs,462pip->pi_nenoffs * sizeof (uint32_t), sizeof (uint32_t));463464dofr.dofr_name = dof_add_string(ddo, pip->pi_rname);465dofr.dofr_type = DOF_RELO_DOFREL;466dofr.dofr_offset = dt_buf_len(&ddo->ddo_probes);467dofr.dofr_data = 0;468469dt_buf_write(dtp, &ddo->ddo_rels, &dofr,470sizeof (dofr), sizeof (uint64_t));471472dt_buf_write(dtp, &ddo->ddo_probes, &dofpr,473sizeof (dofpr), sizeof (uint64_t));474}475476return (0);477}478479static int480dof_add_provider(dt_dof_t *ddo, const dt_provider_t *pvp)481{482dtrace_hdl_t *dtp = ddo->ddo_hdl;483dof_provider_t dofpv;484dof_relohdr_t dofr;485dof_secidx_t *dofs;486ulong_t xr, nxr;487size_t sz;488id_t i;489490if (pvp->pv_flags & DT_PROVIDER_IMPL) {491/*492* ignore providers that are exported by dtrace(7D)493*/494return (0);495}496497nxr = dt_popcb(pvp->pv_xrefs, pvp->pv_xrmax);498dofs = alloca(sizeof (dof_secidx_t) * (nxr + 1));499xr = 1; /* reserve dofs[0] for the provider itself */500501/*502* For each translator referenced by the provider (pv_xrefs), emit an503* exported translator section for it if one hasn't been created yet.504*/505for (i = 0; i < pvp->pv_xrmax; i++) {506if (BT_TEST(pvp->pv_xrefs, i) &&507dtp->dt_xlatemode == DT_XL_DYNAMIC) {508dof_add_translator(ddo,509dt_xlator_lookup_id(dtp, i), DOF_SECT_XLEXPORT);510dofs[xr++] = ddo->ddo_xlexport[i];511}512}513514dt_buf_reset(dtp, &ddo->ddo_probes);515dt_buf_reset(dtp, &ddo->ddo_args);516dt_buf_reset(dtp, &ddo->ddo_offs);517dt_buf_reset(dtp, &ddo->ddo_enoffs);518dt_buf_reset(dtp, &ddo->ddo_rels);519520(void) dt_idhash_iter(pvp->pv_probes, dof_add_probe, ddo);521522if (dt_buf_len(&ddo->ddo_probes) == 0)523return (dt_set_errno(dtp, EDT_NOPROBES));524525dofpv.dofpv_probes = dof_add_lsect(ddo, NULL, DOF_SECT_PROBES,526sizeof (uint64_t), 0, sizeof (dof_probe_t),527dt_buf_len(&ddo->ddo_probes));528529dt_buf_concat(dtp, &ddo->ddo_ldata,530&ddo->ddo_probes, sizeof (uint64_t));531532dofpv.dofpv_prargs = dof_add_lsect(ddo, NULL, DOF_SECT_PRARGS,533sizeof (uint8_t), 0, sizeof (uint8_t), dt_buf_len(&ddo->ddo_args));534535dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_args, sizeof (uint8_t));536537dofpv.dofpv_proffs = dof_add_lsect(ddo, NULL, DOF_SECT_PROFFS,538sizeof (uint_t), 0, sizeof (uint_t), dt_buf_len(&ddo->ddo_offs));539540dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_offs, sizeof (uint_t));541542if ((sz = dt_buf_len(&ddo->ddo_enoffs)) != 0) {543dofpv.dofpv_prenoffs = dof_add_lsect(ddo, NULL,544DOF_SECT_PRENOFFS, sizeof (uint_t), 0, sizeof (uint_t), sz);545} else {546dofpv.dofpv_prenoffs = DOF_SECT_NONE;547}548549dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_enoffs, sizeof (uint_t));550551dofpv.dofpv_strtab = ddo->ddo_strsec;552dofpv.dofpv_name = dof_add_string(ddo, pvp->pv_desc.dtvd_name);553554dofpv.dofpv_provattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_provider);555dofpv.dofpv_modattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_mod);556dofpv.dofpv_funcattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_func);557dofpv.dofpv_nameattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_name);558dofpv.dofpv_argsattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_args);559560dofs[0] = dof_add_lsect(ddo, &dofpv, DOF_SECT_PROVIDER,561sizeof (dof_secidx_t), 0, 0, sizeof (dof_provider_t));562563dofr.dofr_strtab = dofpv.dofpv_strtab;564dofr.dofr_tgtsec = dofpv.dofpv_probes;565dofr.dofr_relsec = dof_add_lsect(ddo, NULL, DOF_SECT_RELTAB,566sizeof (uint64_t), 0, sizeof (dof_relodesc_t),567dt_buf_len(&ddo->ddo_rels));568569dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_rels, sizeof (uint64_t));570571(void) dof_add_lsect(ddo, &dofr, DOF_SECT_URELHDR,572sizeof (dof_secidx_t), 0, 0, sizeof (dof_relohdr_t));573574if (nxr != 0 && dtp->dt_xlatemode == DT_XL_DYNAMIC) {575(void) dof_add_lsect(ddo, dofs, DOF_SECT_PREXPORT,576sizeof (dof_secidx_t), 0, sizeof (dof_secidx_t),577sizeof (dof_secidx_t) * (nxr + 1));578}579580return (0);581}582583static int584dof_hdr(dtrace_hdl_t *dtp, uint8_t dofversion, dof_hdr_t *hp)585{586/*587* If our config values cannot fit in a uint8_t, we can't generate a588* DOF header since the values won't fit. This can only happen if the589* user forcibly compiles a program with an artificial configuration.590*/591if (dtp->dt_conf.dtc_difversion > UINT8_MAX ||592dtp->dt_conf.dtc_difintregs > UINT8_MAX ||593dtp->dt_conf.dtc_diftupregs > UINT8_MAX)594return (dt_set_errno(dtp, EOVERFLOW));595596bzero(hp, sizeof (dof_hdr_t));597598hp->dofh_ident[DOF_ID_MAG0] = DOF_MAG_MAG0;599hp->dofh_ident[DOF_ID_MAG1] = DOF_MAG_MAG1;600hp->dofh_ident[DOF_ID_MAG2] = DOF_MAG_MAG2;601hp->dofh_ident[DOF_ID_MAG3] = DOF_MAG_MAG3;602603if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64)604hp->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_LP64;605else606hp->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_ILP32;607608hp->dofh_ident[DOF_ID_ENCODING] = DOF_ENCODE_NATIVE;609hp->dofh_ident[DOF_ID_VERSION] = dofversion;610hp->dofh_ident[DOF_ID_DIFVERS] = dtp->dt_conf.dtc_difversion;611hp->dofh_ident[DOF_ID_DIFIREG] = dtp->dt_conf.dtc_difintregs;612hp->dofh_ident[DOF_ID_DIFTREG] = dtp->dt_conf.dtc_diftupregs;613614hp->dofh_hdrsize = sizeof (dof_hdr_t);615hp->dofh_secsize = sizeof (dof_sec_t);616hp->dofh_secoff = sizeof (dof_hdr_t);617618return (0);619}620621void *622dtrace_dof_create(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t flags)623{624dt_dof_t *ddo = &dtp->dt_dof;625626const dtrace_ecbdesc_t *edp, *last;627const dtrace_probedesc_t *pdp;628const dtrace_actdesc_t *ap;629const dt_stmt_t *stp;630631uint_t maxacts = 0;632uint_t maxfmt = 0;633634dt_provider_t *pvp;635dt_xlator_t *dxp;636dof_actdesc_t *dofa;637dof_sec_t *sp;638size_t ssize, lsize;639dof_hdr_t h;640641dt_buf_t dof;642char *fmt;643uint_t i;644645if (flags & ~DTRACE_D_MASK) {646(void) dt_set_errno(dtp, EINVAL);647return (NULL);648}649650flags |= dtp->dt_dflags;651652if (dof_hdr(dtp, pgp->dp_dofversion, &h) != 0)653return (NULL);654655if (dt_dof_reset(dtp, pgp) != 0)656return (NULL);657658/*659* Iterate through the statement list computing the maximum number of660* actions and the maximum format string for allocating local buffers.661*/662for (last = NULL, stp = dt_list_next(&pgp->dp_stmts);663stp != NULL; stp = dt_list_next(stp), last = edp) {664665dtrace_stmtdesc_t *sdp = stp->ds_desc;666dtrace_actdesc_t *ap = sdp->dtsd_action;667668if (sdp->dtsd_fmtdata != NULL) {669i = dtrace_printf_format(dtp,670sdp->dtsd_fmtdata, NULL, 0);671maxfmt = MAX(maxfmt, i);672}673674if ((edp = sdp->dtsd_ecbdesc) == last)675continue; /* same ecb as previous statement */676677for (i = 0, ap = edp->dted_action; ap; ap = ap->dtad_next)678i++;679680maxacts = MAX(maxacts, i);681}682683dofa = alloca(sizeof (dof_actdesc_t) * maxacts);684fmt = alloca(maxfmt + 1);685686ddo->ddo_strsec = dof_add_lsect(ddo, NULL, DOF_SECT_STRTAB, 1, 0, 0, 0);687(void) dof_add_string(ddo, "");688689/*690* If there are references to dynamic translators in the program, add691* an imported translator table entry for each referenced translator.692*/693if (pgp->dp_xrefslen != 0) {694for (dxp = dt_list_next(&dtp->dt_xlators);695dxp != NULL; dxp = dt_list_next(dxp)) {696if (dxp->dx_id < pgp->dp_xrefslen &&697pgp->dp_xrefs[dxp->dx_id] != NULL)698dof_add_translator(ddo, dxp, DOF_SECT_XLIMPORT);699}700}701702/*703* Now iterate through the statement list, creating the DOF section704* headers and data for each one and adding them to our buffers.705*/706for (last = NULL, stp = dt_list_next(&pgp->dp_stmts);707stp != NULL; stp = dt_list_next(stp), last = edp) {708709dof_secidx_t probesec = DOF_SECIDX_NONE;710dof_secidx_t prdsec = DOF_SECIDX_NONE;711dof_secidx_t actsec = DOF_SECIDX_NONE;712713const dt_stmt_t *next = stp;714dtrace_stmtdesc_t *sdp = stp->ds_desc;715dof_stridx_t strndx = 0;716dof_probedesc_t dofp;717dof_ecbdesc_t dofe;718uint_t i;719720if ((edp = stp->ds_desc->dtsd_ecbdesc) == last)721continue; /* same ecb as previous statement */722723pdp = &edp->dted_probe;724725/*726* Add a DOF_SECT_PROBEDESC for the ECB's probe description,727* and copy the probe description strings into the string table.728*/729dofp.dofp_strtab = ddo->ddo_strsec;730dofp.dofp_provider = dof_add_string(ddo, pdp->dtpd_provider);731dofp.dofp_mod = dof_add_string(ddo, pdp->dtpd_mod);732dofp.dofp_func = dof_add_string(ddo, pdp->dtpd_func);733dofp.dofp_name = dof_add_string(ddo, pdp->dtpd_name);734dofp.dofp_id = pdp->dtpd_id;735736probesec = dof_add_lsect(ddo, &dofp, DOF_SECT_PROBEDESC,737sizeof (dof_secidx_t), 0,738sizeof (dof_probedesc_t), sizeof (dof_probedesc_t));739740/*741* If there is a predicate DIFO associated with the ecbdesc,742* write out the DIFO sections and save the DIFO section index.743*/744if (edp->dted_pred.dtpdd_difo != NULL)745prdsec = dof_add_difo(ddo, edp->dted_pred.dtpdd_difo);746747/*748* Now iterate through the action list generating DIFOs as749* referenced therein and adding action descriptions to 'dofa'.750*/751for (i = 0, ap = edp->dted_action;752ap != NULL; ap = ap->dtad_next, i++) {753754if (ap->dtad_difo != NULL) {755dofa[i].dofa_difo =756dof_add_difo(ddo, ap->dtad_difo);757} else758dofa[i].dofa_difo = DOF_SECIDX_NONE;759760/*761* If the first action in a statement has string data,762* add the string to the global string table. This can763* be due either to a printf() format string764* (dtsd_fmtdata) or a print() type string765* (dtsd_strdata).766*/767if (sdp != NULL && ap == sdp->dtsd_action) {768if (sdp->dtsd_fmtdata != NULL) {769(void) dtrace_printf_format(dtp,770sdp->dtsd_fmtdata, fmt, maxfmt + 1);771strndx = dof_add_string(ddo, fmt);772} else if (sdp->dtsd_strdata != NULL) {773strndx = dof_add_string(ddo,774sdp->dtsd_strdata);775} else {776strndx = 0; /* use dtad_arg instead */777}778779if ((next = dt_list_next(next)) != NULL)780sdp = next->ds_desc;781else782sdp = NULL;783}784785if (strndx != 0) {786dofa[i].dofa_arg = strndx;787dofa[i].dofa_strtab = ddo->ddo_strsec;788} else {789dofa[i].dofa_arg = ap->dtad_arg;790dofa[i].dofa_strtab = DOF_SECIDX_NONE;791}792793dofa[i].dofa_kind = ap->dtad_kind;794dofa[i].dofa_ntuple = ap->dtad_ntuple;795dofa[i].dofa_uarg = ap->dtad_uarg;796}797798if (i > 0) {799actsec = dof_add_lsect(ddo, dofa, DOF_SECT_ACTDESC,800sizeof (uint64_t), 0, sizeof (dof_actdesc_t),801sizeof (dof_actdesc_t) * i);802}803804/*805* Now finally, add the DOF_SECT_ECBDESC referencing all the806* previously created sub-sections.807*/808dofe.dofe_probes = probesec;809dofe.dofe_pred = prdsec;810dofe.dofe_actions = actsec;811dofe.dofe_pad = 0;812dofe.dofe_uarg = edp->dted_uarg;813814(void) dof_add_lsect(ddo, &dofe, DOF_SECT_ECBDESC,815sizeof (uint64_t), 0, 0, sizeof (dof_ecbdesc_t));816}817818/*819* If any providers are user-defined, output DOF sections corresponding820* to the providers and the probes and arguments that they define.821*/822if (flags & DTRACE_D_PROBES) {823for (pvp = dt_list_next(&dtp->dt_provlist);824pvp != NULL; pvp = dt_list_next(pvp)) {825if (dof_add_provider(ddo, pvp) != 0)826return (NULL);827}828}829830/*831* If we're not stripping unloadable sections, generate compiler832* comments and any other unloadable miscellany.833*/834if (!(flags & DTRACE_D_STRIP)) {835(void) dof_add_usect(ddo, _dtrace_version, DOF_SECT_COMMENTS,836sizeof (char), 0, 0, strlen(_dtrace_version) + 1);837(void) dof_add_usect(ddo, &dtp->dt_uts, DOF_SECT_UTSNAME,838sizeof (char), 0, 0, sizeof (struct utsname));839}840841/*842* Compute and fill in the appropriate values for the dof_hdr_t's843* dofh_secnum, dofh_loadsz, and dofh_filez values.844*/845h.dofh_secnum = ddo->ddo_nsecs;846ssize = sizeof (h) + dt_buf_len(&ddo->ddo_secs);847848h.dofh_loadsz = ssize +849dt_buf_len(&ddo->ddo_ldata) +850dt_buf_len(&ddo->ddo_strs);851852if (dt_buf_len(&ddo->ddo_udata) != 0) {853lsize = roundup(h.dofh_loadsz, sizeof (uint64_t));854h.dofh_filesz = lsize + dt_buf_len(&ddo->ddo_udata);855} else {856lsize = h.dofh_loadsz;857h.dofh_filesz = lsize;858}859860/*861* Set the global DOF_SECT_STRTAB's offset to be after the header,862* section headers, and other loadable data. Since we're going to863* iterate over the buffer data directly, we must check for errors.864*/865if ((i = dt_buf_error(&ddo->ddo_secs)) != 0) {866(void) dt_set_errno(dtp, i);867return (NULL);868}869870sp = dt_buf_ptr(&ddo->ddo_secs);871assert(sp[ddo->ddo_strsec].dofs_type == DOF_SECT_STRTAB);872assert(ssize == sizeof (h) + sizeof (dof_sec_t) * ddo->ddo_nsecs);873874sp[ddo->ddo_strsec].dofs_offset = ssize + dt_buf_len(&ddo->ddo_ldata);875sp[ddo->ddo_strsec].dofs_size = dt_buf_len(&ddo->ddo_strs);876877/*878* Now relocate all the other section headers by adding the appropriate879* delta to their respective dofs_offset values.880*/881for (i = 0; i < ddo->ddo_nsecs; i++, sp++) {882if (i == ddo->ddo_strsec)883continue; /* already relocated above */884885if (sp->dofs_flags & DOF_SECF_LOAD)886sp->dofs_offset += ssize;887else888sp->dofs_offset += lsize;889}890891/*892* Finally, assemble the complete in-memory DOF buffer by writing the893* header and then concatenating all our buffers. dt_buf_concat() will894* propagate any errors and cause dt_buf_claim() to return NULL.895*/896dt_buf_create(dtp, &dof, "dof", h.dofh_filesz);897898dt_buf_write(dtp, &dof, &h, sizeof (h), sizeof (uint64_t));899dt_buf_concat(dtp, &dof, &ddo->ddo_secs, sizeof (uint64_t));900dt_buf_concat(dtp, &dof, &ddo->ddo_ldata, sizeof (uint64_t));901dt_buf_concat(dtp, &dof, &ddo->ddo_strs, sizeof (char));902dt_buf_concat(dtp, &dof, &ddo->ddo_udata, sizeof (uint64_t));903904return (dt_buf_claim(dtp, &dof));905}906907void908dtrace_dof_destroy(dtrace_hdl_t *dtp, void *dof)909{910dt_free(dtp, dof);911}912913void *914dtrace_getopt_dof(dtrace_hdl_t *dtp)915{916dof_hdr_t *dof;917dof_sec_t *sec;918dof_optdesc_t *dofo;919int i, nopts = 0, len = sizeof (dof_hdr_t) +920roundup(sizeof (dof_sec_t), sizeof (uint64_t));921922for (i = 0; i < DTRACEOPT_MAX; i++) {923if (dtp->dt_options[i] != DTRACEOPT_UNSET)924nopts++;925}926927len += sizeof (dof_optdesc_t) * nopts;928929if ((dof = dt_zalloc(dtp, len)) == NULL ||930dof_hdr(dtp, DOF_VERSION, dof) != 0) {931dt_free(dtp, dof);932return (NULL);933}934935dof->dofh_secnum = 1; /* only DOF_SECT_OPTDESC */936dof->dofh_loadsz = len;937dof->dofh_filesz = len;938939/*940* Fill in the option section header...941*/942sec = (dof_sec_t *)((uintptr_t)dof + sizeof (dof_hdr_t));943sec->dofs_type = DOF_SECT_OPTDESC;944sec->dofs_align = sizeof (uint64_t);945sec->dofs_flags = DOF_SECF_LOAD;946sec->dofs_entsize = sizeof (dof_optdesc_t);947948dofo = (dof_optdesc_t *)((uintptr_t)sec +949roundup(sizeof (dof_sec_t), sizeof (uint64_t)));950951sec->dofs_offset = (uintptr_t)dofo - (uintptr_t)dof;952sec->dofs_size = sizeof (dof_optdesc_t) * nopts;953954for (i = 0; i < DTRACEOPT_MAX; i++) {955if (dtp->dt_options[i] == DTRACEOPT_UNSET)956continue;957958dofo->dofo_option = i;959dofo->dofo_strtab = DOF_SECIDX_NONE;960dofo->dofo_value = dtp->dt_options[i];961dofo++;962}963964return (dof);965}966967void *968dtrace_geterr_dof(dtrace_hdl_t *dtp)969{970if (dtp->dt_errprog != NULL)971return (dtrace_dof_create(dtp, dtp->dt_errprog, 0));972973(void) dt_set_errno(dtp, EDT_BADERROR);974return (NULL);975}976977978