int dtrace_stop(dtrace_hdl_t *dtp) { int gen = dtp->dt_statusgen; if (dtp->dt_stopped) return (0); if (dt_ioctl(dtp, DTRACEIOC_STOP, &dtp->dt_endedon) == -1) return (dt_set_errno(dtp, errno)); dtp->dt_stopped = 1; /* * Now that we're stopped, we're going to get status one final time. */ if (dt_ioctl(dtp, DTRACEIOC_STATUS, &dtp->dt_status[gen]) == -1) return (dt_set_errno(dtp, errno)); if (dt_handle_status(dtp, &dtp->dt_status[gen ^ 1], &dtp->dt_status[gen]) == -1) return (-1); return (0); }
int dtrace_go(dtrace_hdl_t *dtp) { dtrace_enable_io_t args; void *dof; int error, r; if (dtp->dt_active) return (dt_set_errno(dtp, EINVAL)); /* * If a dtrace:::ERROR program and callback are registered, enable the * program before we start tracing. If this fails for a vector open * with ENOTTY, we permit dtrace_go() to succeed so that vector clients * such as mdb's dtrace module can execute the rest of dtrace_go() even * though they do not provide support for the DTRACEIOC_ENABLE ioctl. */ if (dtp->dt_errprog != NULL && dtrace_program_exec(dtp, dtp->dt_errprog, NULL) == -1 && ( dtp->dt_errno != ENOTTY || dtp->dt_vector == NULL)) return (-1); /* dt_errno has been set for us */ if ((dof = dtrace_getopt_dof(dtp)) == NULL) return (-1); /* dt_errno has been set for us */ args.dof = dof; args.n_matched = 0; r = dt_ioctl(dtp, DTRACEIOC_ENABLE, &args); error = errno; dtrace_dof_destroy(dtp, dof); if (r == -1 && (error != ENOTTY || dtp->dt_vector == NULL)) return (dt_set_errno(dtp, error)); if (dt_ioctl(dtp, DTRACEIOC_GO, &dtp->dt_beganon) == -1) { if (errno == EACCES) return (dt_set_errno(dtp, EDT_DESTRUCTIVE)); if (errno == EALREADY) return (dt_set_errno(dtp, EDT_ISANON)); if (errno == ENOENT) return (dt_set_errno(dtp, EDT_NOANON)); if (errno == E2BIG) return (dt_set_errno(dtp, EDT_ENDTOOBIG)); if (errno == ENOSPC) return (dt_set_errno(dtp, EDT_BUFTOOSMALL)); return (dt_set_errno(dtp, errno)); } dtp->dt_active = 1; if (dt_options_load(dtp) == -1) return (dt_set_errno(dtp, errno)); return (dt_aggregate_go(dtp)); }
int dt_options_load(dtrace_hdl_t *dtp) { dof_hdr_t hdr, *dof; dof_sec_t *sec; size_t offs; int i; /* * To load the option values, we need to ask the kernel to provide its * DOF, which we'll sift through to look for OPTDESC sections. */ bzero(&hdr, sizeof (dof_hdr_t)); hdr.dofh_loadsz = sizeof (dof_hdr_t); if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &hdr) == -1) return (dt_set_errno(dtp, errno)); if (hdr.dofh_loadsz < sizeof (dof_hdr_t)) return (dt_set_errno(dtp, EINVAL)); dof = alloca(hdr.dofh_loadsz); bzero(dof, sizeof (dof_hdr_t)); dof->dofh_loadsz = hdr.dofh_loadsz; for (i = 0; i < DTRACEOPT_MAX; i++) dtp->dt_options[i] = DTRACEOPT_UNSET; if (dt_ioctl(dtp, DTRACEIOC_DOFGET, dof) == -1) return (dt_set_errno(dtp, errno)); for (i = 0; i < dof->dofh_secnum; i++) { sec = (dof_sec_t *)(uintptr_t)((uintptr_t)dof + dof->dofh_secoff + i * dof->dofh_secsize); if (sec->dofs_type != DOF_SECT_OPTDESC) continue; break; } for (offs = 0; offs < sec->dofs_size; offs += sec->dofs_entsize) { dof_optdesc_t *opt = (dof_optdesc_t *)(uintptr_t) ((uintptr_t)dof + sec->dofs_offset + offs); if (opt->dofo_strtab != DOF_SECIDX_NONE) continue; if (opt->dofo_option >= DTRACEOPT_MAX) continue; dtp->dt_options[opt->dofo_option] = opt->dofo_value; } return (0); }
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); }
int dt_pid_create_probes_module(dtrace_hdl_t *dtp, dt_proc_t *dpr) { dtrace_prog_t *pgp; dt_stmt_t *stp; dtrace_probedesc_t *pdp, pd; pid_t pid; int ret = 0, found = B_FALSE; char provname[DTRACE_PROVNAMELEN]; (void) snprintf(provname, sizeof (provname), "pid%d", (int)dpr->dpr_pid); for (pgp = dt_list_next(&dtp->dt_programs); pgp != NULL; pgp = dt_list_next(pgp)) { for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = dt_list_next(stp)) { pdp = &stp->ds_desc->dtsd_ecbdesc->dted_probe; pid = dt_pid_get_pid(pdp, dtp, NULL, dpr); if (pid != dpr->dpr_pid) continue; found = B_TRUE; pd = *pdp; if (gmatch(provname, pdp->dtpd_provider) != 0 && dt_pid_create_pid_probes(&pd, dtp, NULL, dpr) != 0) ret = 1; /* * If it's not strictly a pid provider, we might match * a USDT provider. */ if (strcmp(provname, pdp->dtpd_provider) != 0 && dt_pid_create_usdt_probes(&pd, dtp, NULL, dpr) != 0) ret = 1; } } if (found) { /* * Give DTrace a shot to the ribs to get it to check * out the newly created probes. */ (void) dt_ioctl(dtp, DTRACEIOC_ENABLE, NULL); } return (ret); }
int dtrace_status(dtrace_hdl_t *dtp) { int gen = dtp->dt_statusgen; dtrace_optval_t interval = dtp->dt_options[DTRACEOPT_STATUSRATE]; hrtime_t now = gethrtime(); if (!dtp->dt_active) return (DTRACE_STATUS_NONE); if (dtp->dt_stopped) return (DTRACE_STATUS_STOPPED); if (dtp->dt_laststatus != 0) { if (now - dtp->dt_laststatus < interval) return (DTRACE_STATUS_NONE); dtp->dt_laststatus += interval; } else { dtp->dt_laststatus = now; } if (dt_ioctl(dtp, DTRACEIOC_STATUS, &dtp->dt_status[gen]) == -1) return (dt_set_errno(dtp, errno)); dtp->dt_statusgen ^= 1; if (dt_handle_status(dtp, &dtp->dt_status[dtp->dt_statusgen], &dtp->dt_status[gen]) == -1) return (-1); if (dtp->dt_status[gen].dtst_exiting) { if (!dtp->dt_stopped) (void) dtrace_stop(dtp); return (DTRACE_STATUS_EXITED); } if (dtp->dt_status[gen].dtst_filled == 0) return (DTRACE_STATUS_OKAY); if (dtp->dt_options[DTRACEOPT_BUFPOLICY] != DTRACEOPT_BUFPOLICY_FILL) return (DTRACE_STATUS_OKAY); if (!dtp->dt_stopped) { if (dtrace_stop(dtp) == -1) return (-1); } return (DTRACE_STATUS_FILLED); }
struct ps_prochandle * dtrace_proc_waitfor(dtrace_hdl_t *dtp, char const *pname) { dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target"); struct ps_prochandle *P = NULL; int err; dtrace_procdesc_t pdesc; assert(dtp); assert(pname); assert(*pname != '\0'); size_t max_len = sizeof(pdesc.p_comm); if (strlcpy(pdesc.p_comm, pname, max_len) >= max_len) { fprintf(stderr, "Error, the process name (%s) exceeded the %lu characters limit\n", pname, sizeof(pdesc.p_comm) - 1); return NULL; } if ((err = dt_ioctl(dtp, DTRACEIOC_PROCWAITFOR, &pdesc)) != 0) { fprintf(stderr, "Error, dt_ioctl() failed (%s)\n", strerror(errno)); return NULL; } assert(pdesc.p_pid != -1); /* * The process is already stopped by the previous ioctl call. * The function dt_proc_grab() will stop and resume the process, * but the process will remain stopped until we call pid_resume(). */ P = dt_proc_grab(dtp, pdesc.p_pid, 0, 0); /* Waking-up a process can fail if there is another client waiting for the same process. */ if ((err = pid_resume(pdesc.p_pid)) != 0) { dt_dprintf("Unable to resume the process (pid=%d), the process is still suspended\n", pdesc.p_pid); } if (P != NULL && idp != NULL && idp->di_id == 0) idp->di_id = pdesc.p_pid; /* $target = grabbed pid */ return P; }
int dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_proginfo_t *pip) { void *dof; int n, err; dtrace_program_info(dtp, pgp, pip); if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL) return (-1); n = dt_ioctl(dtp, DTRACEIOC_ENABLE, dof); #if defined(__APPLE__) if (n == -1 && (errno & 0xfffff000)) n = (((unsigned int)errno) >> 12); /* Darwin's ioctls only return -1 or zero. Overload errno to mimic Solaris. */ #endif /* __APPLE__ */ dtrace_dof_destroy(dtp, dof); if (n == -1) { switch (errno) { case EINVAL: err = EDT_DIFINVAL; break; case EFAULT: err = EDT_DIFFAULT; break; case E2BIG: err = EDT_DIFSIZE; break; case EBUSY: err = EDT_ENABLING_ERR; break; default: err = errno; } return (dt_set_errno(dtp, err)); } if (pip != NULL) pip->dpi_matches += n; return (0); }
int dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_proginfo_t *pip) { dtrace_enable_io_t args; void *dof; int n, err; dtrace_program_info(dtp, pgp, pip); if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL) return (-1); args.dof = dof; args.n_matched = 0; n = dt_ioctl(dtp, DTRACEIOC_ENABLE, &args); dtrace_dof_destroy(dtp, dof); if (n == -1) { switch (errno) { case EINVAL: err = EDT_DIFINVAL; break; case EFAULT: err = EDT_DIFFAULT; break; case E2BIG: err = EDT_DIFSIZE; break; case EBUSY: err = EDT_ENABLING_ERR; break; default: err = errno; } return (dt_set_errno(dtp, err)); } if (pip != NULL) pip->dpi_matches += args.n_matched; return (0); }
/* * 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); }
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)); } }
/* * 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); }
static int dt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id) { dtrace_id_t max; int rval, i; dtrace_eprobedesc_t *enabled, *nenabled; dtrace_probedesc_t *probe; while (id >= (max = dtp->dt_maxprobe) || dtp->dt_pdesc == NULL) { dtrace_id_t new_max = max ? (max << 1) : 1; size_t nsize = new_max * sizeof (void *); dtrace_probedesc_t **new_pdesc; dtrace_eprobedesc_t **new_edesc; if ((new_pdesc = malloc(nsize)) == NULL || (new_edesc = malloc(nsize)) == NULL) { free(new_pdesc); return (dt_set_errno(dtp, EDT_NOMEM)); } bzero(new_pdesc, nsize); bzero(new_edesc, nsize); if (dtp->dt_pdesc != NULL) { size_t osize = max * sizeof (void *); bcopy(dtp->dt_pdesc, new_pdesc, osize); free(dtp->dt_pdesc); bcopy(dtp->dt_edesc, new_edesc, osize); free(dtp->dt_edesc); } dtp->dt_pdesc = new_pdesc; dtp->dt_edesc = new_edesc; dtp->dt_maxprobe = new_max; } if (dtp->dt_pdesc[id] != NULL) return (0); if ((enabled = malloc(sizeof (dtrace_eprobedesc_t))) == NULL) return (dt_set_errno(dtp, EDT_NOMEM)); bzero(enabled, sizeof (dtrace_eprobedesc_t)); enabled->dtepd_epid = id; enabled->dtepd_nrecs = 1; #if defined(sun) if (dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled) == -1) { #else if (dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled) == -1) { #endif rval = dt_set_errno(dtp, errno); free(enabled); return (rval); } if (DTRACE_SIZEOF_EPROBEDESC(enabled) != sizeof (*enabled)) { /* * There must be more than one action. Allocate the * appropriate amount of space and try again. */ if ((nenabled = malloc(DTRACE_SIZEOF_EPROBEDESC(enabled))) != NULL) bcopy(enabled, nenabled, sizeof (*enabled)); free(enabled); if ((enabled = nenabled) == NULL) return (dt_set_errno(dtp, EDT_NOMEM)); #if defined(sun) rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled); #else rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled); #endif if (rval == -1) { rval = dt_set_errno(dtp, errno); free(enabled); return (rval); } } if ((probe = malloc(sizeof (dtrace_probedesc_t))) == NULL) { free(enabled); return (dt_set_errno(dtp, EDT_NOMEM)); } probe->dtpd_id = enabled->dtepd_probeid; if (dt_ioctl(dtp, DTRACEIOC_PROBES, probe) == -1) { rval = dt_set_errno(dtp, errno); goto err; } for (i = 0; i < enabled->dtepd_nrecs; i++) { dtrace_recdesc_t *rec = &enabled->dtepd_rec[i]; if (DTRACEACT_ISPRINTFLIKE(rec->dtrd_action)) { if (dt_strdata_add(dtp, rec, &dtp->dt_formats, &dtp->dt_maxformat) != 0) { rval = -1; goto err; } } else if (rec->dtrd_action == DTRACEACT_DIFEXPR) { if (dt_strdata_add(dtp, rec, (void ***)&dtp->dt_strdata, &dtp->dt_maxstrdata) != 0) { rval = -1; goto err; } } } dtp->dt_pdesc[id] = probe; dtp->dt_edesc[id] = enabled; return (0); err: /* * If we failed, free our allocated probes. Note that if we failed * while allocating formats, we aren't going to free formats that * we have already allocated. This is okay; these formats are * hanging off of dt_formats and will therefore not be leaked. */ free(enabled); free(probe); return (rval); } int dt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid, dtrace_eprobedesc_t **epdp, dtrace_probedesc_t **pdp) { int rval; if (epid >= dtp->dt_maxprobe || dtp->dt_pdesc[epid] == NULL) { if ((rval = dt_epid_add(dtp, epid)) != 0) return (rval); } assert(epid < dtp->dt_maxprobe); assert(dtp->dt_edesc[epid] != NULL); assert(dtp->dt_pdesc[epid] != NULL); *epdp = dtp->dt_edesc[epid]; *pdp = dtp->dt_pdesc[epid]; return (0); }
static int dt_aggid_add(dtrace_hdl_t *dtp, dtrace_aggid_t id) { dtrace_id_t max; dtrace_epid_t epid; int rval; while (id >= (max = dtp->dt_maxagg) || dtp->dt_aggdesc == NULL) { dtrace_id_t new_max = max ? (max << 1) : 1; size_t nsize = new_max * sizeof (void *); dtrace_aggdesc_t **new_aggdesc; if ((new_aggdesc = malloc(nsize)) == NULL) return (dt_set_errno(dtp, EDT_NOMEM)); bzero(new_aggdesc, nsize); if (dtp->dt_aggdesc != NULL) { bcopy(dtp->dt_aggdesc, new_aggdesc, max * sizeof (void *)); free(dtp->dt_aggdesc); } dtp->dt_aggdesc = new_aggdesc; dtp->dt_maxagg = new_max; } if (dtp->dt_aggdesc[id] == NULL) { dtrace_aggdesc_t *agg, *nagg; if ((agg = malloc(sizeof (dtrace_aggdesc_t))) == NULL) return (dt_set_errno(dtp, EDT_NOMEM)); bzero(agg, sizeof (dtrace_aggdesc_t)); agg->dtagd_id = id; agg->dtagd_nrecs = 1; #if defined(sun) if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg) == -1) { #else if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg) == -1) { #endif rval = dt_set_errno(dtp, errno); free(agg); return (rval); } if (DTRACE_SIZEOF_AGGDESC(agg) != sizeof (*agg)) { /* * There must be more than one action. Allocate the * appropriate amount of space and try again. */ if ((nagg = malloc(DTRACE_SIZEOF_AGGDESC(agg))) != NULL) bcopy(agg, nagg, sizeof (*agg)); free(agg); if ((agg = nagg) == NULL) return (dt_set_errno(dtp, EDT_NOMEM)); #if defined(sun) rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg); #else rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg); #endif if (rval == -1) { rval = dt_set_errno(dtp, errno); free(agg); return (rval); } } /* * If we have a uarg, it's a pointer to the compiler-generated * statement; we'll use this value to get the name and * compiler-generated variable ID for the aggregation. If * we're grabbing an anonymous enabling, this pointer value * is obviously meaningless -- and in this case, we can't * provide the compiler-generated aggregation information. */ if (dtp->dt_options[DTRACEOPT_GRABANON] == DTRACEOPT_UNSET && agg->dtagd_rec[0].dtrd_uarg != 0) { dtrace_stmtdesc_t *sdp; dt_ident_t *aid; sdp = (dtrace_stmtdesc_t *)(uintptr_t) agg->dtagd_rec[0].dtrd_uarg; aid = sdp->dtsd_aggdata; agg->dtagd_name = aid->di_name; agg->dtagd_varid = aid->di_id; } else { agg->dtagd_varid = DTRACE_AGGVARIDNONE; } if ((epid = agg->dtagd_epid) >= dtp->dt_maxprobe || dtp->dt_pdesc[epid] == NULL) { if ((rval = dt_epid_add(dtp, epid)) != 0) { free(agg); return (rval); } } dtp->dt_aggdesc[id] = agg; } return (0); } int dt_aggid_lookup(dtrace_hdl_t *dtp, dtrace_aggid_t aggid, dtrace_aggdesc_t **adp) { int rval; if (aggid >= dtp->dt_maxagg || dtp->dt_aggdesc[aggid] == NULL) { if ((rval = dt_aggid_add(dtp, aggid)) != 0) return (rval); } assert(aggid < dtp->dt_maxagg); assert(dtp->dt_aggdesc[aggid] != NULL); *adp = dtp->dt_aggdesc[aggid]; return (0); }
static int dt_strdata_add(dtrace_hdl_t *dtp, dtrace_recdesc_t *rec, void ***data, int *max) { int maxformat; dtrace_fmtdesc_t fmt; void *result; if (rec->dtrd_format == 0) return (0); if (rec->dtrd_format <= *max && (*data)[rec->dtrd_format - 1] != NULL) { return (0); } bzero(&fmt, sizeof (fmt)); fmt.dtfd_format = rec->dtrd_format; fmt.dtfd_string = NULL; fmt.dtfd_length = 0; if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) return (dt_set_errno(dtp, errno)); if ((fmt.dtfd_string = dt_alloc(dtp, fmt.dtfd_length)) == NULL) return (dt_set_errno(dtp, EDT_NOMEM)); if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) { free(fmt.dtfd_string); return (dt_set_errno(dtp, errno)); } while (rec->dtrd_format > (maxformat = *max)) { int new_max = maxformat ? (maxformat << 1) : 1; size_t nsize = new_max * sizeof (void *); size_t osize = maxformat * sizeof (void *); void **new_data = dt_zalloc(dtp, nsize); if (new_data == NULL) { dt_free(dtp, fmt.dtfd_string); return (dt_set_errno(dtp, EDT_NOMEM)); } bcopy(*data, new_data, osize); free(*data); *data = new_data; *max = new_max; } switch (rec->dtrd_action) { case DTRACEACT_DIFEXPR: result = fmt.dtfd_string; break; case DTRACEACT_PRINTA: result = dtrace_printa_create(dtp, fmt.dtfd_string); dt_free(dtp, fmt.dtfd_string); break; default: result = dtrace_printf_create(dtp, fmt.dtfd_string); dt_free(dtp, fmt.dtfd_string); break; } if (result == NULL) return (-1); (*data)[rec->dtrd_format - 1] = result; return (0); }
int dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb) { char provname[DTRACE_PROVNAMELEN]; struct ps_prochandle *P; dt_proc_t *dpr; pid_t pid; int err = 0; assert(pcb != NULL); if ((pid = dt_pid_get_pid(pdp, dtp, pcb, NULL)) == -1) return (-1); if (dtp->dt_ftfd == -1) { if (dtp->dt_fterr == ENOENT) { (void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_NODEV, "pid provider is not installed on this system"); } else { (void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_NODEV, "pid provider is not available: %s", strerror(dtp->dt_fterr)); } return (-1); } (void) snprintf(provname, sizeof (provname), "pid%d", (int)pid); if (gmatch(provname, pdp->dtpd_provider) != 0) { if ((P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0)) == NULL) { (void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_GRAB, "failed to grab process %d", (int)pid); return (-1); } dpr = dt_proc_lookup(dtp, P, 0); assert(dpr != NULL); (void) pthread_mutex_lock(&dpr->dpr_lock); if ((err = dt_pid_create_pid_probes(pdp, dtp, pcb, dpr)) == 0) { /* * Alert other retained enablings which may match * against the newly created probes. */ (void) dt_ioctl(dtp, DTRACEIOC_ENABLE, NULL); } (void) pthread_mutex_unlock(&dpr->dpr_lock); dt_proc_release(dtp, P); } /* * If it's not strictly a pid provider, we might match a USDT provider. */ if (strcmp(provname, pdp->dtpd_provider) != 0) { if ((P = dt_proc_grab(dtp, pid, 0, 1)) == NULL) { (void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_GRAB, "failed to grab process %d", (int)pid); return (-1); } dpr = dt_proc_lookup(dtp, P, 0); assert(dpr != NULL); (void) pthread_mutex_lock(&dpr->dpr_lock); if (!dpr->dpr_usdt) { err = dt_pid_create_usdt_probes(pdp, dtp, pcb, dpr); dpr->dpr_usdt = B_TRUE; } (void) pthread_mutex_unlock(&dpr->dpr_lock); dt_proc_release(dtp, P); } return (err ? -1 : 0); }