dt_provider_t * dt_provider_create(dtrace_hdl_t *dtp, const char *name) { dt_provider_t *pvp; if ((pvp = dt_zalloc(dtp, sizeof (dt_provider_t))) == NULL) return (NULL); (void) strlcpy(pvp->pv_desc.dtvd_name, name, DTRACE_PROVNAMELEN); pvp->pv_probes = dt_idhash_create(pvp->pv_desc.dtvd_name, NULL, 0, 0); pvp->pv_gen = dtp->dt_gen; pvp->pv_hdl = dtp; if (pvp->pv_probes == NULL) { dt_free(dtp, pvp); (void) dt_set_errno(dtp, EDT_NOMEM); return (NULL); } pvp->pv_desc.dtvd_attr.dtpa_provider = _dtrace_prvattr; pvp->pv_desc.dtvd_attr.dtpa_mod = _dtrace_prvattr; pvp->pv_desc.dtvd_attr.dtpa_func = _dtrace_prvattr; pvp->pv_desc.dtvd_attr.dtpa_name = _dtrace_prvattr; pvp->pv_desc.dtvd_attr.dtpa_args = _dtrace_prvattr; return (dt_provider_insert(dtp, pvp, dt_strtab_hash(name, NULL) % dtp->dt_provbuckets)); }
struct ps_prochandle * dt_proc_create(dtrace_hdl_t *dtp, const char *file, char *const *argv) { dt_proc_hash_t *dph = dtp->dt_procs; dt_proc_t *dpr; int err; if ((dpr = dt_zalloc(dtp, sizeof (dt_proc_t))) == NULL) return (NULL); /* errno is set for us */ (void) pthread_mutex_init(&dpr->dpr_lock, NULL); (void) pthread_cond_init(&dpr->dpr_cv, NULL); if ((dpr->dpr_proc = Pcreate(file, argv, &err, NULL, 0, dtp->dt_arch)) == NULL) { return (dt_proc_error(dtp, dpr, "failed to execute %s: %s\n", file, Pcreate_error(err))); } dpr->dpr_hdl = dtp; dpr->dpr_pid = Pstatus(dpr->dpr_proc)->pr_pid; (void) Punsetflags(dpr->dpr_proc, PR_RLC); (void) Psetflags(dpr->dpr_proc, PR_KLC); if (dt_proc_create_thread(dtp, dpr, dtp->dt_prcmode) != 0) return (NULL); /* dt_proc_error() has been called for us */ dpr->dpr_hash = dph->dph_hash[dpr->dpr_pid & (dph->dph_hashlen - 1)]; dph->dph_hash[dpr->dpr_pid & (dph->dph_hashlen - 1)] = dpr; dt_list_prepend(&dph->dph_lrulist, dpr); dt_dprintf("created pid %d\n", (int)dpr->dpr_pid); dpr->dpr_refs++; return (dpr->dpr_proc); }
dt_inttab_t * dt_inttab_create(dtrace_hdl_t *dtp) { uint_t len = _dtrace_intbuckets; dt_inttab_t *ip; assert((len & (len - 1)) == 0); if ((ip = dt_zalloc(dtp, sizeof (dt_inttab_t))) == NULL || (ip->int_hash = dt_zalloc(dtp, sizeof (void *) * len)) == NULL) { dt_free(dtp, ip); return (NULL); } ip->int_hdl = dtp; ip->int_hashlen = len; return (ip); }
void * dtrace_getopt_dof(dtrace_hdl_t *dtp) { dof_hdr_t *dof; dof_sec_t *sec; dof_optdesc_t *dofo; int i, nopts = 0, len = sizeof (dof_hdr_t) + roundup(sizeof (dof_sec_t), sizeof (uint64_t)); for (i = 0; i < DTRACEOPT_MAX; i++) { if (dtp->dt_options[i] != DTRACEOPT_UNSET) nopts++; } len += sizeof (dof_optdesc_t) * nopts; if ((dof = dt_zalloc(dtp, len)) == NULL || dof_hdr(dtp, DOF_VERSION, dof) != 0) { dt_free(dtp, dof); return (NULL); } dof->dofh_secnum = 1; /* only DOF_SECT_OPTDESC */ dof->dofh_loadsz = len; dof->dofh_filesz = len; /* * Fill in the option section header... */ sec = (dof_sec_t *)((uintptr_t)dof + sizeof (dof_hdr_t)); sec->dofs_type = DOF_SECT_OPTDESC; sec->dofs_align = sizeof (uint64_t); sec->dofs_flags = DOF_SECF_LOAD; sec->dofs_entsize = sizeof (dof_optdesc_t); dofo = (dof_optdesc_t *)((uintptr_t)sec + roundup(sizeof (dof_sec_t), sizeof (uint64_t))); sec->dofs_offset = (uintptr_t)dofo - (uintptr_t)dof; sec->dofs_size = sizeof (dof_optdesc_t) * nopts; for (i = 0; i < DTRACEOPT_MAX; i++) { if (dtp->dt_options[i] == DTRACEOPT_UNSET) continue; dofo->dofo_option = i; dofo->dofo_strtab = DOF_SECIDX_NONE; dofo->dofo_value = dtp->dt_options[i]; dofo++; } return (dof); }
/*ARGSUSED*/ static int dt_opt_preallocate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) { dtrace_optval_t size; void *p; if (arg == NULL || dt_optval_parse(arg, &size) != 0) return (dt_set_errno(dtp, EDT_BADOPTVAL)); if (size > SIZE_MAX) size = SIZE_MAX; if ((p = dt_zalloc(dtp, size)) == NULL) { do { size /= 2; } while ((p = dt_zalloc(dtp, size)) == NULL); } dt_free(dtp, p); return (0); }
void dt_proc_hash_create(dtrace_hdl_t *dtp) { if ((dtp->dt_procs = dt_zalloc(dtp, sizeof (dt_proc_hash_t) + sizeof (dt_proc_t *) * _dtrace_pidbuckets - 1)) != NULL) { (void) pthread_mutex_init(&dtp->dt_procs->dph_lock, NULL); (void) pthread_cond_init(&dtp->dt_procs->dph_cv, NULL); dtp->dt_procs->dph_hashlen = _dtrace_pidbuckets; dtp->dt_procs->dph_lrulim = _dtrace_pidlrulim; } }
/* * Create a new priority queue. * * size is the maximum number of items that will be stored in the priority * queue at one time. */ dt_pq_t * dt_pq_init(dtrace_hdl_t *dtp, uint_t size, dt_pq_value_f value_cb, void *cb_arg) { dt_pq_t *p; assert(size > 1); if ((p = dt_zalloc(dtp, sizeof (dt_pq_t))) == NULL) return (NULL); p->dtpq_items = dt_zalloc(dtp, size * sizeof (p->dtpq_items[0])); if (p->dtpq_items == NULL) { dt_free(dtp, p); return (NULL); } p->dtpq_hdl = dtp; p->dtpq_size = size; p->dtpq_last = 1; p->dtpq_value = value_cb; p->dtpq_arg = cb_arg; return (p); }
dtrace_ecbdesc_t * dt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp) { dtrace_ecbdesc_t *edp; if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) { (void) dt_set_errno(dtp, EDT_NOMEM); return (NULL); } edp->dted_probe = *pdp; dt_ecbdesc_hold(edp); return (edp); }
/* * Rewrite the xlate/xlarg instruction at dtdo_buf[i] so that the instruction's * xltab index reflects the offset 'xi' of the assigned dtdo_xlmtab[] location. * We track the cumulative references to translators and members in the pcb's * pcb_asxrefs[] array, a two-dimensional array of bitmaps indexed by the * global translator id and then by the corresponding translator member id. */ static void dt_as_xlate(dt_pcb_t *pcb, dtrace_difo_t *dp, uint_t i, uint_t xi, dt_node_t *dnp) { dtrace_hdl_t *dtp = pcb->pcb_hdl; dt_xlator_t *dxp = dnp->dn_membexpr->dn_xlator; assert(i < dp->dtdo_len); assert(xi < dp->dtdo_xlmlen); assert(dnp->dn_kind == DT_NODE_MEMBER); assert(dnp->dn_membexpr->dn_kind == DT_NODE_XLATOR); assert(dxp->dx_id < dtp->dt_xlatorid); assert(dnp->dn_membid < dxp->dx_nmembers); if (pcb->pcb_asxrefs == NULL) { pcb->pcb_asxreflen = dtp->dt_xlatorid; pcb->pcb_asxrefs = dt_zalloc(dtp, sizeof (ulong_t *) * pcb->pcb_asxreflen); if (pcb->pcb_asxrefs == NULL) longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); } if (pcb->pcb_asxrefs[dxp->dx_id] == NULL) { pcb->pcb_asxrefs[dxp->dx_id] = dt_zalloc(dtp, BT_SIZEOFMAP(dxp->dx_nmembers)); if (pcb->pcb_asxrefs[dxp->dx_id] == NULL) longjmp(pcb->pcb_jmpbuf, EDT_NOMEM); } dp->dtdo_buf[i] = DIF_INSTR_XLATE( DIF_INSTR_OP(dp->dtdo_buf[i]), xi, DIF_INSTR_RD(dp->dtdo_buf[i])); BT_SET(pcb->pcb_asxrefs[dxp->dx_id], dnp->dn_membid); dp->dtdo_xlmtab[xi] = dnp; }
dtrace_stmtdesc_t * dtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp) { dtrace_stmtdesc_t *sdp; if ((sdp = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL) return (NULL); dt_ecbdesc_hold(edp); sdp->dtsd_ecbdesc = edp; sdp->dtsd_descattr = _dtrace_defattr; sdp->dtsd_stmtattr = _dtrace_defattr; return (sdp); }
void dt_buf_create(dtrace_hdl_t *dtp, dt_buf_t *bp, const char *name, size_t len) { if (len == 0) len = _dtrace_bufsize; bp->dbu_buf = bp->dbu_ptr = dt_zalloc(dtp, len); bp->dbu_len = len; if (bp->dbu_buf == NULL) bp->dbu_err = dtrace_errno(dtp); else bp->dbu_err = 0; bp->dbu_resizes = 0; bp->dbu_name = name; }
static dt_bkpt_t * dt_proc_bpcreate(dt_proc_t *dpr, uintptr_t addr, dt_bkpt_f *func, void *data) { struct ps_prochandle *P = dpr->dpr_proc; dt_bkpt_t *dbp; assert(DT_MUTEX_HELD(&dpr->dpr_lock)); if ((dbp = dt_zalloc(dpr->dpr_hdl, sizeof (dt_bkpt_t))) != NULL) { dbp->dbp_func = func; dbp->dbp_data = data; dbp->dbp_addr = addr; if (Psetbkpt(P, dbp->dbp_addr, &dbp->dbp_instr) == 0) dbp->dbp_active = B_TRUE; dt_list_append(&dpr->dpr_bps, dbp); } return (dbp); }
dtrace_prog_t * dt_program_create(dtrace_hdl_t *dtp) { dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t)); if (pgp != NULL) { dt_list_append(&dtp->dt_programs, pgp); } else { (void) dt_set_errno(dtp, EDT_NOMEM); return (NULL); } /* * By default, programs start with DOF version 1 so that output files * containing DOF are backward compatible. If a program requires new * DOF features, the version is increased as needed. */ pgp->dp_dofversion = DOF_VERSION_1; return (pgp); }
void dt_buf_write(dtrace_hdl_t *dtp, dt_buf_t *bp, const void *buf, size_t len, size_t align) { size_t off = (size_t)(bp->dbu_ptr - bp->dbu_buf); size_t adj = roundup(off, align) - off; if (bp->dbu_err != 0) { (void) dt_set_errno(dtp, bp->dbu_err); return; /* write silently fails */ } if (bp->dbu_ptr + adj + len > bp->dbu_buf + bp->dbu_len) { size_t new_len = bp->dbu_len * 2; uchar_t *new_buf; uint_t r = 1; while (bp->dbu_ptr + adj + len > bp->dbu_buf + new_len) { new_len *= 2; r++; } if ((new_buf = dt_zalloc(dtp, new_len)) == NULL) { bp->dbu_err = dtrace_errno(dtp); return; } bcopy(bp->dbu_buf, new_buf, off); dt_free(dtp, bp->dbu_buf); bp->dbu_buf = new_buf; bp->dbu_ptr = new_buf + off; bp->dbu_len = new_len; bp->dbu_resizes += r; } bp->dbu_ptr += adj; bcopy(buf, bp->dbu_ptr, len); bp->dbu_ptr += len; }
dtrace_prog_t * dt_program_create(dtrace_hdl_t *dtp) { dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t)); if (pgp != NULL) dt_list_append(&dtp->dt_programs, pgp); else (void) dt_set_errno(dtp, EDT_NOMEM); /* * By default, programs start with DOF version 1 so that output files * containing DOF are backward compatible. If a program requires new * DOF features, the version is increased as needed. */ /* * APPLE NOTE: The earliest DOF version Leopard will support is v3. * This includes relative offsets for probes, and is-enabled probes. */ pgp->dp_dofversion = DOF_VERSION_3; return (pgp); }
int dt_provider_xref(dtrace_hdl_t *dtp, dt_provider_t *pvp, id_t id) { size_t oldsize = BT_SIZEOFMAP(pvp->pv_xrmax); size_t newsize = BT_SIZEOFMAP(dtp->dt_xlatorid); assert(id >= 0 && id < dtp->dt_xlatorid); if (newsize > oldsize) { ulong_t *xrefs = dt_zalloc(dtp, newsize); if (xrefs == NULL) return (-1); bcopy(pvp->pv_xrefs, xrefs, oldsize); dt_free(dtp, pvp->pv_xrefs); pvp->pv_xrefs = xrefs; pvp->pv_xrmax = dtp->dt_xlatorid; } BT_SET(pvp->pv_xrefs, id); return (0); }
int dt_probe_define(dt_provider_t *pvp, dt_probe_t *prp, const char *fname, const char *rname, uint32_t offset, int isenabled) { dtrace_hdl_t *dtp = pvp->pv_hdl; dt_probe_instance_t *pip; uint32_t **offs; uint_t *noffs, *maxoffs; assert(fname != NULL); for (pip = prp->pr_inst; pip != NULL; pip = pip->pi_next) { if (strcmp(pip->pi_fname, fname) == 0 && ((rname == NULL && pip->pi_rname == NULL) || (rname != NULL && pip->pi_rname != NULL && strcmp(pip->pi_rname, rname) == 0))) break; } if (pip == NULL) { if ((pip = dt_zalloc(dtp, sizeof (*pip))) == NULL) return (-1); if ((pip->pi_offs = dt_zalloc(dtp, sizeof (uint32_t))) == NULL) goto nomem; if ((pip->pi_enoffs = dt_zalloc(dtp, sizeof (uint32_t))) == NULL) goto nomem; if ((pip->pi_fname = strdup(fname)) == NULL) goto nomem; if (rname != NULL && (pip->pi_rname = strdup(rname)) == NULL) goto nomem; pip->pi_noffs = 0; pip->pi_maxoffs = 1; pip->pi_nenoffs = 0; pip->pi_maxenoffs = 1; pip->pi_next = prp->pr_inst; prp->pr_inst = pip; } if (isenabled) { offs = &pip->pi_enoffs; noffs = &pip->pi_nenoffs; maxoffs = &pip->pi_maxenoffs; } else { offs = &pip->pi_offs; noffs = &pip->pi_noffs; maxoffs = &pip->pi_maxoffs; } if (*noffs == *maxoffs) { uint_t new_max = *maxoffs * 2; uint32_t *new_offs = dt_alloc(dtp, sizeof (uint32_t) * new_max); if (new_offs == NULL) return (-1); bcopy(*offs, new_offs, sizeof (uint32_t) * *maxoffs); dt_free(dtp, *offs); *maxoffs = new_max; *offs = new_offs; } dt_dprintf("defined probe %s %s:%s %s() +0x%x (%s)\n", isenabled ? "(is-enabled)" : "", pvp->pv_desc.dtvd_name, prp->pr_ident->di_name, fname, offset, rname != NULL ? rname : fname); assert(*noffs < *maxoffs); (*offs)[(*noffs)++] = offset; return (0); nomem: dt_free(dtp, pip->pi_fname); dt_free(dtp, pip->pi_enoffs); dt_free(dtp, pip->pi_offs); dt_free(dtp, pip); return (dt_set_errno(dtp, EDT_NOMEM)); }
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); }
dt_xlator_t * dt_xlator_create(dtrace_hdl_t *dtp, const dtrace_typeinfo_t *src, const dtrace_typeinfo_t *dst, const char *name, dt_node_t *members, dt_node_t *nodes) { dt_xlator_t *dxp = dt_zalloc(dtp, sizeof (dt_xlator_t)); dtrace_typeinfo_t ptr = *dst; dt_xlator_t **map; dt_node_t *dnp; uint_t kind; if (dxp == NULL) return (NULL); dxp->dx_hdl = dtp; dxp->dx_id = dtp->dt_xlatorid++; dxp->dx_gen = dtp->dt_gen; dxp->dx_arg = -1; if ((map = dt_alloc(dtp, sizeof (void *) * (dxp->dx_id + 1))) == NULL) { dt_free(dtp, dxp); return (NULL); } dt_list_append(&dtp->dt_xlators, dxp); bcopy(dtp->dt_xlatormap, map, sizeof (void *) * dxp->dx_id); dt_free(dtp, dtp->dt_xlatormap); dtp->dt_xlatormap = map; dtp->dt_xlatormap[dxp->dx_id] = dxp; if (dt_type_pointer(&ptr) == -1) { ptr.dtt_ctfp = NULL; ptr.dtt_type = CTF_ERR; } dxp->dx_ident = dt_ident_create(name ? name : "T", DT_IDENT_SCALAR, DT_IDFLG_REF | DT_IDFLG_ORPHAN, 0, _dtrace_defattr, 0, &dt_idops_thaw, NULL, dtp->dt_gen); if (dxp->dx_ident == NULL) goto err; /* no memory for identifier */ dxp->dx_ident->di_ctfp = src->dtt_ctfp; dxp->dx_ident->di_type = src->dtt_type; /* * If an input parameter name is given, this is a static translator * definition: create an idhash and identifier for the parameter. */ if (name != NULL) { dxp->dx_locals = dt_idhash_create("xlparams", NULL, 0, 0); if (dxp->dx_locals == NULL) goto err; /* no memory for identifier hash */ dt_idhash_xinsert(dxp->dx_locals, dxp->dx_ident); } dxp->dx_souid.di_name = "translator"; dxp->dx_souid.di_kind = DT_IDENT_XLSOU; dxp->dx_souid.di_flags = DT_IDFLG_REF; dxp->dx_souid.di_id = dxp->dx_id; dxp->dx_souid.di_attr = _dtrace_defattr; dxp->dx_souid.di_ops = &dt_idops_thaw; dxp->dx_souid.di_data = dxp; dxp->dx_souid.di_ctfp = dst->dtt_ctfp; dxp->dx_souid.di_type = dst->dtt_type; dxp->dx_souid.di_gen = dtp->dt_gen; dxp->dx_ptrid.di_name = "translator"; dxp->dx_ptrid.di_kind = DT_IDENT_XLPTR; dxp->dx_ptrid.di_flags = DT_IDFLG_REF; dxp->dx_ptrid.di_id = dxp->dx_id; dxp->dx_ptrid.di_attr = _dtrace_defattr; dxp->dx_ptrid.di_ops = &dt_idops_thaw; dxp->dx_ptrid.di_data = dxp; dxp->dx_ptrid.di_ctfp = ptr.dtt_ctfp; dxp->dx_ptrid.di_type = ptr.dtt_type; dxp->dx_ptrid.di_gen = dtp->dt_gen; /* * If a deferred pragma is pending on the keyword "translator", run all * the deferred pragmas on dx_souid and then copy results to dx_ptrid. * See the code in dt_pragma.c for details on deferred ident pragmas. */ if (dtp->dt_globals->dh_defer != NULL && yypcb->pcb_pragmas != NULL && dt_idhash_lookup(yypcb->pcb_pragmas, "translator") != NULL) { dtp->dt_globals->dh_defer(dtp->dt_globals, &dxp->dx_souid); dxp->dx_ptrid.di_attr = dxp->dx_souid.di_attr; dxp->dx_ptrid.di_vers = dxp->dx_souid.di_vers; } dxp->dx_src_ctfp = src->dtt_ctfp; dxp->dx_src_type = src->dtt_type; dxp->dx_src_base = ctf_type_resolve(src->dtt_ctfp, src->dtt_type); dxp->dx_dst_ctfp = dst->dtt_ctfp; dxp->dx_dst_type = dst->dtt_type; dxp->dx_dst_base = ctf_type_resolve(dst->dtt_ctfp, dst->dtt_type); kind = ctf_type_kind(dst->dtt_ctfp, dxp->dx_dst_base); assert(kind == CTF_K_STRUCT || kind == CTF_K_UNION); /* * If no input parameter is given, we're making a dynamic translator: * create member nodes for every member of the output type. Otherwise * retain the member and allocation node lists presented by the parser. */ if (name == NULL) { if (ctf_member_iter(dxp->dx_dst_ctfp, dxp->dx_dst_base, dt_xlator_create_member, dxp) != 0) goto err; } else { dxp->dx_members = members; dxp->dx_nodes = nodes; } /* * Assign member IDs to each member and allocate space for DIFOs * if and when this translator is eventually compiled. */ for (dnp = dxp->dx_members; dnp != NULL; dnp = dnp->dn_list) { dnp->dn_membxlator = dxp; dnp->dn_membid = dxp->dx_nmembers++; } dxp->dx_membdif = dt_zalloc(dtp, sizeof (dtrace_difo_t *) * dxp->dx_nmembers); if (dxp->dx_membdif == NULL) { dxp->dx_nmembers = 0; goto err; } return (dxp); err: dt_xlator_destroy(dtp, dxp); return (NULL); }
struct ps_prochandle * dt_proc_grab(dtrace_hdl_t *dtp, pid_t pid, int flags, int nomonitor) { dt_proc_hash_t *dph = dtp->dt_procs; uint_t h = pid & (dph->dph_hashlen - 1); dt_proc_t *dpr, *opr; int err; /* * Search the hash table for the pid. If it is already grabbed or * created, move the handle to the front of the lrulist, increment * the reference count, and return the existing ps_prochandle. */ for (dpr = dph->dph_hash[h]; dpr != NULL; dpr = dpr->dpr_hash) { if (dpr->dpr_pid == pid && !dpr->dpr_stale) { /* * If the cached handle was opened read-only and * this request is for a writeable handle, mark * the cached handle as stale and open a new handle. * Since it's stale, unmark it as cacheable. */ if (dpr->dpr_rdonly && !(flags & PGRAB_RDONLY)) { dt_dprintf("upgrading pid %d\n", (int)pid); dpr->dpr_stale = B_TRUE; dpr->dpr_cacheable = B_FALSE; dph->dph_lrucnt--; break; } dt_dprintf("grabbed pid %d (cached)\n", (int)pid); dt_list_delete(&dph->dph_lrulist, dpr); dt_list_prepend(&dph->dph_lrulist, dpr); dpr->dpr_refs++; return (dpr->dpr_proc); } } if ((dpr = dt_zalloc(dtp, sizeof (dt_proc_t))) == NULL) return (NULL); /* errno is set for us */ (void) pthread_mutex_init(&dpr->dpr_lock, NULL); (void) pthread_cond_init(&dpr->dpr_cv, NULL); //printf("grabbing pid %d\n", pid); if ((dpr->dpr_proc = Pgrab(pid, flags, &err)) == NULL) { return (dt_proc_error(dtp, dpr, "failed to grab pid %d: %s\n", (int)pid, Pgrab_error(err))); } dpr->dpr_hdl = dtp; dpr->dpr_pid = pid; (void) Punsetflags(dpr->dpr_proc, PR_KLC); (void) Psetflags(dpr->dpr_proc, PR_RLC); /* * If we are attempting to grab the process without a monitor * thread, then mark the process cacheable only if it's being * grabbed read-only. If we're currently caching more process * handles than dph_lrulim permits, attempt to find the * least-recently-used handle that is currently unreferenced and * release it from the cache. Otherwise we are grabbing the process * for control: create a control thread for this process and store * its ID in dpr->dpr_tid. */ if (nomonitor || (flags & PGRAB_RDONLY)) { if (dph->dph_lrucnt >= dph->dph_lrulim) { for (opr = dt_list_prev(&dph->dph_lrulist); opr != NULL; opr = dt_list_prev(opr)) { if (opr->dpr_cacheable && opr->dpr_refs == 0) { dt_proc_destroy(dtp, opr->dpr_proc); break; } } } if (flags & PGRAB_RDONLY) { dpr->dpr_cacheable = B_TRUE; dpr->dpr_rdonly = B_TRUE; dph->dph_lrucnt++; } } else if (dt_proc_create_thread(dtp, dpr, DT_PROC_STOP_GRAB) != 0) return (NULL); /* dt_proc_error() has been called for us */ dpr->dpr_hash = dph->dph_hash[h]; dph->dph_hash[h] = dpr; dt_list_prepend(&dph->dph_lrulist, dpr); dt_dprintf("grabbed pid %d\n", (int)pid); dpr->dpr_refs++; return (dpr->dpr_proc); }
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); }