/* * Cook an associative array identifier. If this is the first time we are * cooking this array, create its signature based on the argument list. * Otherwise validate the argument list against the existing signature. */ static void dt_idcook_assc(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args) { if (idp->di_data == NULL) { dt_idsig_t *isp = idp->di_data = malloc(sizeof (dt_idsig_t)); char n[DT_TYPE_NAMELEN]; int i; if (isp == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); isp->dis_varargs = -1; isp->dis_optargs = -1; isp->dis_argc = argc; isp->dis_args = NULL; isp->dis_auxinfo = 0; if (argc != 0 && (isp->dis_args = calloc(argc, sizeof (dt_node_t))) == NULL) { idp->di_data = NULL; free(isp); longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); } /* * If this identifier has not been explicitly declared earlier, * set the identifier's base type to be our special type <DYN>. * If this ident is an aggregation, it will remain as is. If * this ident is an associative array, it will be reassigned * based on the result type of the first assignment statement. */ if (!(idp->di_flags & DT_IDFLG_DECL)) { idp->di_ctfp = DT_DYN_CTFP(yypcb->pcb_hdl); idp->di_type = DT_DYN_TYPE(yypcb->pcb_hdl); } for (i = 0; i < argc; i++, args = args->dn_list) { if (dt_node_is_dynamic(args) || dt_node_is_void(args)) { xyerror(D_KEY_TYPE, "%s expression may not be " "used as %s index: key #%d\n", dt_node_type_name(args, n, sizeof (n)), dt_idkind_name(idp->di_kind), i + 1); } dt_node_type_propagate(args, &isp->dis_args[i]); isp->dis_args[i].dn_list = &isp->dis_args[i + 1]; } if (argc != 0) isp->dis_args[argc - 1].dn_list = NULL; dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type); } else { dt_idcook_sign(dnp, idp, argc, args, idp->di_kind == DT_IDENT_AGG ? "@" : "", "[ ]"); } }
/* * 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); }