/* * Return a boolean value indicating if two types are compatible integers or * floating-pointer values. This function returns true if the two types are * the same, or if they have the same ASCII name and encoding properties. * This function could be extended to test for compatibility for other kinds. */ int ctf_type_compat(ctf_file_t *lfp, ctf_id_t ltype, ctf_file_t *rfp, ctf_id_t rtype) { const ctf_type_t *ltp, *rtp; ctf_encoding_t le, re; ctf_arinfo_t la, ra; uint_t lkind, rkind; if (ctf_type_cmp(lfp, ltype, rfp, rtype) == 0) return (1); ltype = ctf_type_resolve(lfp, ltype); lkind = ctf_type_kind(lfp, ltype); rtype = ctf_type_resolve(rfp, rtype); rkind = ctf_type_kind(rfp, rtype); if (lkind != rkind || (ltp = ctf_lookup_by_id(&lfp, ltype)) == NULL || (rtp = ctf_lookup_by_id(&rfp, rtype)) == NULL || strcmp(ctf_strptr(lfp, ltp->ctt_name), ctf_strptr(rfp, rtp->ctt_name)) != 0) return (0); switch (lkind) { case CTF_K_INTEGER: case CTF_K_FLOAT: return (ctf_type_encoding(lfp, ltype, &le) == 0 && ctf_type_encoding(rfp, rtype, &re) == 0 && bcmp(&le, &re, sizeof (ctf_encoding_t)) == 0); case CTF_K_POINTER: return (ctf_type_compat(lfp, ctf_type_reference(lfp, ltype), rfp, ctf_type_reference(rfp, rtype))); case CTF_K_ARRAY: return (ctf_array_info(lfp, ltype, &la) == 0 && ctf_array_info(rfp, rtype, &ra) == 0 && la.ctr_nelems == ra.ctr_nelems && ctf_type_compat( lfp, la.ctr_contents, rfp, ra.ctr_contents) && ctf_type_compat(lfp, la.ctr_index, rfp, ra.ctr_index)); case CTF_K_STRUCT: case CTF_K_UNION: return (ctf_type_size(lfp, ltype) == ctf_type_size(rfp, rtype)); case CTF_K_ENUM: case CTF_K_FORWARD: return (1); /* no other checks required for these type kinds */ default: return (0); /* should not get here since we did a resolve */ } }
dt_xlator_t * dt_xlator_lookup(dtrace_hdl_t *dtp, dt_node_t *src, dt_node_t *dst, int flags) { ctf_file_t *src_ctfp = src->dn_ctfp; ctf_id_t src_type = src->dn_type; ctf_id_t src_base = ctf_type_resolve(src_ctfp, src_type); ctf_file_t *dst_ctfp = dst->dn_ctfp; ctf_id_t dst_type = dst->dn_type; ctf_id_t dst_base = ctf_type_resolve(dst_ctfp, dst_type); uint_t dst_kind = ctf_type_kind(dst_ctfp, dst_base); int ptr = dst_kind == CTF_K_POINTER; dtrace_typeinfo_t src_dtt, dst_dtt; dt_node_t xn = { 0 }; dt_xlator_t *dxp = NULL; if (src_base == CTF_ERR || dst_base == CTF_ERR) return (NULL); /* fail if these are unresolvable types */ /* * Translators are always defined using a struct or union type, so if * we are attempting to translate to type "T *", we internally look * for a translation to type "T" by following the pointer reference. */ if (ptr) { dst_type = ctf_type_reference(dst_ctfp, dst_type); dst_base = ctf_type_resolve(dst_ctfp, dst_type); dst_kind = ctf_type_kind(dst_ctfp, dst_base); } if (dst_kind != CTF_K_UNION && dst_kind != CTF_K_STRUCT) return (NULL); /* fail if the output isn't a struct or union */ /* * In order to find a matching translator, we iterate over the set of * available translators in three passes. First, we look for a * translation from the exact source type to the resolved destination. * Second, we look for a translation from the resolved source type to * the resolved destination. Third, we look for a translation from a * compatible source type (using the same rules as parameter formals) * to the resolved destination. If all passes fail, return NULL. */ for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL; dxp = dt_list_next(dxp)) { if (ctf_type_compat(dxp->dx_src_ctfp, dxp->dx_src_type, src_ctfp, src_type) && ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base, dst_ctfp, dst_base)) goto out; } if (flags & DT_XLATE_EXACT) goto out; /* skip remaining passes if exact match required */ for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL; dxp = dt_list_next(dxp)) { if (ctf_type_compat(dxp->dx_src_ctfp, dxp->dx_src_base, src_ctfp, src_type) && ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base, dst_ctfp, dst_base)) goto out; } for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL; dxp = dt_list_next(dxp)) { dt_node_type_assign(&xn, dxp->dx_src_ctfp, dxp->dx_src_type); if (ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base, dst_ctfp, dst_base) && dt_node_is_argcompat(src, &xn)) goto out; } out: if (ptr && dxp != NULL && dxp->dx_ptrid.di_type == CTF_ERR) return (NULL); /* no translation available to pointer type */ if (dxp != NULL || !(flags & DT_XLATE_EXTERN) || dtp->dt_xlatemode == DT_XL_STATIC) return (dxp); /* we succeeded or not allowed to extern */ /* * If we get here, then we didn't find an existing translator, but the * caller and xlatemode permit us to create an extern to a dynamic one. */ src_dtt.dtt_object = dt_module_lookup_by_ctf(dtp, src_ctfp)->dm_name; src_dtt.dtt_ctfp = src_ctfp; src_dtt.dtt_type = src_type; dst_dtt.dtt_object = dt_module_lookup_by_ctf(dtp, dst_ctfp)->dm_name; dst_dtt.dtt_ctfp = dst_ctfp; dst_dtt.dtt_type = dst_type; return (dt_xlator_create(dtp, &src_dtt, &dst_dtt, NULL, NULL, NULL)); }