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)); } }
/* * Pop the topmost PCB from the PCB stack and destroy any data structures that * are associated with it. If 'err' is non-zero, destroy any intermediate * state that is left behind as part of a compilation that has failed. */ void dt_pcb_pop(dtrace_hdl_t *dtp, int err) { dt_pcb_t *pcb = yypcb; uint_t i; assert(pcb != NULL); assert(pcb == dtp->dt_pcb); while (pcb->pcb_dstack.ds_next != NULL) (void) dt_scope_pop(); dt_scope_destroy(&pcb->pcb_dstack); dt_irlist_destroy(&pcb->pcb_ir); dt_node_link_free(&pcb->pcb_list); dt_node_link_free(&pcb->pcb_hold); if (err != 0) { dt_xlator_t *dxp, *nxp; dt_provider_t *pvp, *nvp; if (pcb->pcb_prog != NULL) dt_program_destroy(dtp, pcb->pcb_prog); if (pcb->pcb_stmt != NULL) dtrace_stmt_destroy(dtp, pcb->pcb_stmt); if (pcb->pcb_ecbdesc != NULL) dt_ecbdesc_release(dtp, pcb->pcb_ecbdesc); for (dxp = dt_list_next(&dtp->dt_xlators); dxp; dxp = nxp) { nxp = dt_list_next(dxp); if (dxp->dx_gen == dtp->dt_gen) dt_xlator_destroy(dtp, dxp); } for (pvp = dt_list_next(&dtp->dt_provlist); pvp; pvp = nvp) { nvp = dt_list_next(pvp); if (pvp->pv_gen == dtp->dt_gen) dt_provider_destroy(dtp, pvp); } (void) dt_idhash_iter(dtp->dt_aggs, dt_pcb_pop_ident, dtp); dt_idhash_update(dtp->dt_aggs); (void) dt_idhash_iter(dtp->dt_globals, dt_pcb_pop_ident, dtp); dt_idhash_update(dtp->dt_globals); (void) dt_idhash_iter(dtp->dt_tls, dt_pcb_pop_ident, dtp); dt_idhash_update(dtp->dt_tls); (void) ctf_discard(dtp->dt_cdefs->dm_ctfp); (void) ctf_discard(dtp->dt_ddefs->dm_ctfp); } if (pcb->pcb_pragmas != NULL) dt_idhash_destroy(pcb->pcb_pragmas); if (pcb->pcb_locals != NULL) dt_idhash_destroy(pcb->pcb_locals); if (pcb->pcb_idents != NULL) dt_idhash_destroy(pcb->pcb_idents); if (pcb->pcb_inttab != NULL) dt_inttab_destroy(pcb->pcb_inttab); if (pcb->pcb_strtab != NULL) dt_strtab_destroy(pcb->pcb_strtab); if (pcb->pcb_regs != NULL) dt_regset_destroy(pcb->pcb_regs); for (i = 0; i < pcb->pcb_asxreflen; i++) dt_free(dtp, pcb->pcb_asxrefs[i]); dt_free(dtp, pcb->pcb_asxrefs); dt_difo_free(dtp, pcb->pcb_difo); free(pcb->pcb_filetag); free(pcb->pcb_sflagv); dtp->dt_pcb = pcb->pcb_prev; bzero(pcb, sizeof (dt_pcb_t)); yyinit(dtp->dt_pcb); }
dtrace_difo_t * dt_as(dt_pcb_t *pcb) { dtrace_hdl_t *dtp = pcb->pcb_hdl; dt_irlist_t *dlp = &pcb->pcb_ir; uint_t *labels = NULL; dt_irnode_t *dip; dtrace_difo_t *dp; dt_ident_t *idp; size_t n = 0; uint_t i; uint_t kmask, kbits, umask, ubits; uint_t krel = 0, urel = 0, xlrefs = 0; /* * Select bitmasks based upon the desired symbol linking policy. We * test (di_extern->di_flags & xmask) == xbits to determine if the * symbol should have a relocation entry generated in the loop below. * * DT_LINK_KERNEL = kernel symbols static, user symbols dynamic * DT_LINK_PRIMARY = primary kernel symbols static, others dynamic * DT_LINK_DYNAMIC = all symbols dynamic * DT_LINK_STATIC = all symbols static * * By 'static' we mean that we use the symbol's value at compile-time * in the final DIF. By 'dynamic' we mean that we create a relocation * table entry for the symbol's value so it can be relocated later. */ switch (dtp->dt_linkmode) { case DT_LINK_KERNEL: kmask = 0; kbits = -1u; umask = DT_IDFLG_USER; ubits = DT_IDFLG_USER; break; case DT_LINK_PRIMARY: kmask = DT_IDFLG_USER | DT_IDFLG_PRIM; kbits = 0; umask = DT_IDFLG_USER; ubits = DT_IDFLG_USER; break; case DT_LINK_DYNAMIC: kmask = DT_IDFLG_USER; kbits = 0; umask = DT_IDFLG_USER; ubits = DT_IDFLG_USER; break; case DT_LINK_STATIC: kmask = umask = 0; kbits = ubits = -1u; break; default: xyerror(D_UNKNOWN, "internal error -- invalid link mode %u\n", dtp->dt_linkmode); } assert(pcb->pcb_difo == NULL); pcb->pcb_difo = dt_zalloc(dtp, sizeof (dtrace_difo_t)); if ((dp = pcb->pcb_difo) == NULL) longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); dp->dtdo_buf = dt_alloc(dtp, sizeof (dif_instr_t) * dlp->dl_len); if (dp->dtdo_buf == NULL) longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); if ((labels = dt_alloc(dtp, sizeof (uint_t) * dlp->dl_label)) == NULL) longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); /* * Make an initial pass through the instruction list, filling in the * instruction buffer with valid instructions and skipping labeled nops. * While doing this, we also fill in our labels[] translation table * and we count up the number of relocation table entries we will need. */ for (i = 0, dip = dlp->dl_list; dip != NULL; dip = dip->di_next) { if (dip->di_label != DT_LBL_NONE) labels[dip->di_label] = i; if (dip->di_label == DT_LBL_NONE || dip->di_instr != DIF_INSTR_NOP) dp->dtdo_buf[i++] = dip->di_instr; if (dip->di_extern == NULL) continue; /* no external references needed */ switch (DIF_INSTR_OP(dip->di_instr)) { case DIF_OP_SETX: idp = dip->di_extern; if ((idp->di_flags & kmask) == kbits) krel++; else if ((idp->di_flags & umask) == ubits) urel++; break; case DIF_OP_XLATE: case DIF_OP_XLARG: xlrefs++; break; default: xyerror(D_UNKNOWN, "unexpected assembler relocation " "for opcode 0x%x\n", DIF_INSTR_OP(dip->di_instr)); } } assert(i == dlp->dl_len); dp->dtdo_len = dlp->dl_len; /* * Make a second pass through the instructions, relocating each branch * label to the index of the final instruction in the buffer and noting * any other instruction-specific DIFO flags such as dtdo_destructive. */ for (i = 0; i < dp->dtdo_len; i++) { dif_instr_t instr = dp->dtdo_buf[i]; uint_t op = DIF_INSTR_OP(instr); if (op == DIF_OP_CALL) { if (DIF_INSTR_SUBR(instr) == DIF_SUBR_COPYOUT || DIF_INSTR_SUBR(instr) == DIF_SUBR_COPYOUTSTR) dp->dtdo_destructive = 1; continue; } if (op >= DIF_OP_BA && op <= DIF_OP_BLEU) { assert(DIF_INSTR_LABEL(instr) < dlp->dl_label); dp->dtdo_buf[i] = DIF_INSTR_BRANCH(op, labels[DIF_INSTR_LABEL(instr)]); } } dt_free(dtp, labels); pcb->pcb_asvidx = 0; /* * Allocate memory for the appropriate number of variable records and * then fill in each variable record. As we populate the variable * table we insert the corresponding variable names into the strtab. */ (void) dt_idhash_iter(dtp->dt_tls, dt_countvar, &n); (void) dt_idhash_iter(dtp->dt_globals, dt_countvar, &n); (void) dt_idhash_iter(pcb->pcb_locals, dt_countvar, &n); if (n != 0) { dp->dtdo_vartab = dt_alloc(dtp, n * sizeof (dtrace_difv_t)); dp->dtdo_varlen = (uint32_t)n; if (dp->dtdo_vartab == NULL) longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); (void) dt_idhash_iter(dtp->dt_tls, dt_copyvar, pcb); (void) dt_idhash_iter(dtp->dt_globals, dt_copyvar, pcb); (void) dt_idhash_iter(pcb->pcb_locals, dt_copyvar, pcb); } /* * Allocate memory for the appropriate number of relocation table * entries based upon our kernel and user counts from the first pass. */ if (krel != 0) { dp->dtdo_kreltab = dt_alloc(dtp, krel * sizeof (dof_relodesc_t)); dp->dtdo_krelen = krel; if (dp->dtdo_kreltab == NULL) longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); } if (urel != 0) { dp->dtdo_ureltab = dt_alloc(dtp, urel * sizeof (dof_relodesc_t)); dp->dtdo_urelen = urel; if (dp->dtdo_ureltab == NULL) longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); } if (xlrefs != 0) { dp->dtdo_xlmtab = dt_zalloc(dtp, sizeof (dt_node_t *) * xlrefs); dp->dtdo_xlmlen = xlrefs; if (dp->dtdo_xlmtab == NULL) longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); } /* * If any relocations are needed, make another pass through the * instruction list and fill in the relocation table entries. */ if (krel + urel + xlrefs != 0) { uint_t knodef = pcb->pcb_cflags & DTRACE_C_KNODEF; uint_t unodef = pcb->pcb_cflags & DTRACE_C_UNODEF; dof_relodesc_t *krp = dp->dtdo_kreltab; dof_relodesc_t *urp = dp->dtdo_ureltab; dt_node_t **xlp = dp->dtdo_xlmtab; i = 0; /* dtdo_buf[] index */ for (dip = dlp->dl_list; dip != NULL; dip = dip->di_next) { dof_relodesc_t *rp; ssize_t soff; uint_t nodef; if (dip->di_label != DT_LBL_NONE && dip->di_instr == DIF_INSTR_NOP) continue; /* skip label declarations */ i++; /* advance dtdo_buf[] index */ if (DIF_INSTR_OP(dip->di_instr) == DIF_OP_XLATE || DIF_INSTR_OP(dip->di_instr) == DIF_OP_XLARG) { assert(dp->dtdo_buf[i - 1] == dip->di_instr); dt_as_xlate(pcb, dp, i - 1, (uint_t) (xlp++ - dp->dtdo_xlmtab), dip->di_extern); continue; } if ((idp = dip->di_extern) == NULL) continue; /* no relocation entry needed */ if ((idp->di_flags & kmask) == kbits) { nodef = knodef; rp = krp++; } else if ((idp->di_flags & umask) == ubits) { nodef = unodef; rp = urp++; } else continue; if (!nodef) dt_as_undef(idp, i); assert(DIF_INSTR_OP(dip->di_instr) == DIF_OP_SETX); soff = dt_strtab_insert(pcb->pcb_strtab, idp->di_name); if (soff == -1L) longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); if (soff > DIF_STROFF_MAX) longjmp(pcb->pcb_jmpbuf, EDT_STR2BIG); rp->dofr_name = (dof_stridx_t)soff; rp->dofr_type = DOF_RELO_SETX; rp->dofr_offset = DIF_INSTR_INTEGER(dip->di_instr) * sizeof (uint64_t); rp->dofr_data = 0; } assert(krp == dp->dtdo_kreltab + dp->dtdo_krelen); assert(urp == dp->dtdo_ureltab + dp->dtdo_urelen); assert(xlp == dp->dtdo_xlmtab + dp->dtdo_xlmlen); assert(i == dp->dtdo_len); } /* * Allocate memory for the compiled string table and then copy the * chunks from the string table into the final string buffer. */ if ((n = dt_strtab_size(pcb->pcb_strtab)) != 0) { if ((dp->dtdo_strtab = dt_alloc(dtp, n)) == NULL) longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); (void) dt_strtab_write(pcb->pcb_strtab, (dt_strtab_write_f *)dt_copystr, pcb); dp->dtdo_strlen = (uint32_t)n; } /* * Allocate memory for the compiled integer table and then copy the * integer constants from the table into the final integer buffer. */ if ((n = dt_inttab_size(pcb->pcb_inttab)) != 0) { if ((dp->dtdo_inttab = dt_alloc(dtp, n * sizeof (uint64_t))) == NULL) longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); dt_inttab_write(pcb->pcb_inttab, dp->dtdo_inttab); dp->dtdo_intlen = (uint32_t)n; } /* * Fill in the DIFO return type from the type associated with the * node saved in pcb_dret, and then clear pcb_difo and pcb_dret * now that the assembler has completed successfully. */ dt_node_diftype(dtp, pcb->pcb_dret, &dp->dtdo_rtype); pcb->pcb_difo = NULL; pcb->pcb_dret = NULL; if (pcb->pcb_cflags & DTRACE_C_DIFV) dt_dis(dp, stderr); return (dp); }
static void 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) return; /* ignore providers that are exported by dtrace(7D) */ 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); 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)); } }