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)); }
void dt_provider_destroy(dtrace_hdl_t *dtp, dt_provider_t *pvp) { dt_provider_t **pp; uint_t h; assert(pvp->pv_hdl == dtp); h = dt_strtab_hash(pvp->pv_desc.dtvd_name, NULL) % dtp->dt_provbuckets; pp = &dtp->dt_provs[h]; while (*pp != NULL && *pp != pvp) pp = &(*pp)->pv_next; assert(*pp != NULL && *pp == pvp); *pp = pvp->pv_next; dt_list_delete(&dtp->dt_provlist, pvp); dtp->dt_nprovs--; if (pvp->pv_probes != NULL) dt_idhash_destroy(pvp->pv_probes); dt_node_link_free(&pvp->pv_nodes); dt_free(dtp, pvp->pv_xrefs); dt_free(dtp, pvp); }
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); }
dt_module_t * dt_module_create(dtrace_hdl_t *dtp, const char *name) { uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets; dt_module_t *dmp; for (dmp = dtp->dt_mods[h]; dmp != NULL; dmp = dmp->dm_next) { if (strcmp(dmp->dm_name, name) == 0) return (dmp); } if ((dmp = malloc(sizeof (dt_module_t))) == NULL) return (NULL); /* caller must handle allocation failure */ bzero(dmp, sizeof (dt_module_t)); (void) strlcpy(dmp->dm_name, name, sizeof (dmp->dm_name)); dt_list_append(&dtp->dt_modlist, dmp); dmp->dm_next = dtp->dt_mods[h]; dtp->dt_mods[h] = dmp; dtp->dt_nmods++; if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64) dmp->dm_ops = &dt_modops_64; else dmp->dm_ops = &dt_modops_32; return (dmp); }
void dt_module_destroy(dtrace_hdl_t *dtp, dt_module_t *dmp) { uint_t h = dt_strtab_hash(dmp->dm_name, NULL) % dtp->dt_modbuckets; dt_module_t **dmpp = &dtp->dt_mods[h]; dt_list_delete(&dtp->dt_modlist, dmp); assert(dtp->dt_nmods != 0); dtp->dt_nmods--; /* * Now remove this module from its hash chain. We expect to always * find the module on its hash chain, so in this loop we assert that * we don't run off the end of the list. */ while (*dmpp != dmp) { dmpp = &((*dmpp)->dm_next); assert(*dmpp != NULL); } *dmpp = dmp->dm_next; dt_module_unload(dtp, dmp); free(dmp); }
static GElf_Sym * dt_module_symname64(dt_module_t *dmp, const char *name, GElf_Sym *symp, uint_t *idp) { const Elf64_Sym *symtab = dmp->dm_symtab.cts_data; const char *strtab = dmp->dm_strtab.cts_data; const Elf64_Sym *sym; const dt_sym_t *dsp; uint_t i, h; if (dmp->dm_nsymelems == 0) return (NULL); h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets; for (i = dmp->dm_symbuckets[h]; i != 0; i = dsp->ds_next) { dsp = &dmp->dm_symchains[i]; sym = symtab + dsp->ds_symid; if (strcmp(name, strtab + sym->st_name) == 0) { if (idp != NULL) *idp = dsp->ds_symid; return (dt_module_symgelf64(sym, symp)); } } return (NULL); }
dt_ident_t * dt_idhash_insert(dt_idhash_t *dhp, const char *name, ushort_t kind, ushort_t flags, uint_t id, dtrace_attribute_t attr, uint_t vers, const dt_idops_t *ops, void *iarg, ulong_t gen) { dt_ident_t *idp; ulong_t h; if (dhp->dh_tmpl != NULL) dt_idhash_populate(dhp); /* fill hash w/ initial population */ idp = dt_ident_create(name, kind, flags, id, attr, vers, ops, iarg, gen); if (idp == NULL) return (NULL); h = dt_strtab_hash(name, NULL) % dhp->dh_hashsz; idp->di_next = dhp->dh_hash[h]; dhp->dh_hash[h] = idp; dhp->dh_nelems++; if (dhp->dh_defer != NULL) dhp->dh_defer(dhp, idp); return (idp); }
dt_module_t * dt_module_create(dtrace_hdl_t *dtp, const char *name) { long pid; char *eptr; dt_ident_t *idp; uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets; dt_module_t *dmp; for (dmp = dtp->dt_mods[h]; dmp != NULL; dmp = dmp->dm_next) { if (strcmp(dmp->dm_name, name) == 0) return (dmp); } if ((dmp = malloc(sizeof (dt_module_t))) == NULL) return (NULL); /* caller must handle allocation failure */ bzero(dmp, sizeof (dt_module_t)); (void) strlcpy(dmp->dm_name, name, sizeof (dmp->dm_name)); dt_list_append(&dtp->dt_modlist, dmp); dmp->dm_next = dtp->dt_mods[h]; dtp->dt_mods[h] = dmp; dtp->dt_nmods++; if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64) dmp->dm_ops = &dt_modops_64; else dmp->dm_ops = &dt_modops_32; /* * Modules for userland processes are special. They always refer to a * specific process and have a copy of their CTF data from a specific * instant in time. Any dt_module_t that begins with 'pid' is a module * for a specific process, much like how any probe description that * begins with 'pid' is special. pid123 refers to process 123. A module * that is just 'pid' refers specifically to pid$target. This is * generally done as D does not currently allow for macros to be * evaluated when working with types. */ if (strncmp(dmp->dm_name, "pid", 3) == 0) { errno = 0; if (dmp->dm_name[3] == '\0') { idp = dt_idhash_lookup(dtp->dt_macros, "target"); if (idp != NULL && idp->di_id != 0) dmp->dm_pid = idp->di_id; } else { pid = strtol(dmp->dm_name + 3, &eptr, 10); if (errno == 0 && *eptr == '\0') dmp->dm_pid = (pid_t)pid; else dt_dprintf("encountered malformed pid " "module: %s\n", dmp->dm_name); } } return (dmp); }
static void dt_module_symhash_insert(dt_module_t *dmp, const char *name, uint_t id) { dt_sym_t *dsp = &dmp->dm_symchains[dmp->dm_symfree]; uint_t h; assert(dmp->dm_symfree < dmp->dm_nsymelems + 1); dsp->ds_symid = id; h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets; dsp->ds_next = dmp->dm_symbuckets[h]; dmp->dm_symbuckets[h] = dmp->dm_symfree++; }
dt_module_t * dt_module_lookup_by_name(dtrace_hdl_t *dtp, const char *name) { uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets; dt_module_t *dmp; for (dmp = dtp->dt_mods[h]; dmp != NULL; dmp = dmp->dm_next) { if (strcmp(dmp->dm_name, name) == 0) return (dmp); } return (NULL); }
dt_ident_t * dt_idhash_lookup(dt_idhash_t *dhp, const char *name) { size_t len; ulong_t h = dt_strtab_hash(name, &len) % dhp->dh_hashsz; dt_ident_t *idp; if (dhp->dh_tmpl != NULL) dt_idhash_populate(dhp); /* fill hash w/ initial population */ for (idp = dhp->dh_hash[h]; idp != NULL; idp = idp->di_next) { if (strcmp(idp->di_name, name) == 0) return (idp); } return (NULL); }
void dt_idhash_xinsert(dt_idhash_t *dhp, dt_ident_t *idp) { ulong_t h; if (dhp->dh_tmpl != NULL) dt_idhash_populate(dhp); /* fill hash w/ initial population */ h = dt_strtab_hash(idp->di_name, NULL) % dhp->dh_hashsz; idp->di_next = dhp->dh_hash[h]; idp->di_flags &= ~DT_IDFLG_ORPHAN; dhp->dh_hash[h] = idp; dhp->dh_nelems++; if (dhp->dh_defer != NULL) dhp->dh_defer(dhp, idp); }
void dt_idhash_delete(dt_idhash_t *dhp, dt_ident_t *key) { size_t len; ulong_t h = dt_strtab_hash(key->di_name, &len) % dhp->dh_hashsz; dt_ident_t **pp = &dhp->dh_hash[h]; dt_ident_t *idp; for (idp = dhp->dh_hash[h]; idp != NULL; idp = idp->di_next) { if (idp == key) break; else pp = &idp->di_next; } assert(idp == key); *pp = idp->di_next; assert(dhp->dh_nelems != 0); dhp->dh_nelems--; if (!(idp->di_flags & DT_IDFLG_ORPHAN)) dt_ident_destroy(idp); }
static GElf_Sym * dt_module_symname_macho_64(dt_module_t *dmp, const char *name, GElf_Sym *symp, uint_t *idp) { const struct nlist_64 *symtab = (const struct nlist_64 *)(dmp->dm_symtab.cts_data); const char *strtab = (const char *)dmp->dm_strtab.cts_data; const struct nlist_64 *sym; const dt_sym_t *dsp; uint_t i, h; if (dmp->dm_nsymelems == 0) return (NULL); h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets; for (i = dmp->dm_symbuckets[h]; i != 0; i = dsp->ds_next) { dsp = &dmp->dm_symchains[i]; sym = symtab + dsp->ds_symid; const char *sname = strtab + sym->n_un.n_strx; if ('_' == sname[0]) sname++; // Lop off omnipresent underscore if (strcmp(name, sname) == 0) { if (idp != NULL) *idp = dsp->ds_symid; symp->st_name = (GElf_Sxword)(sname - strtab); symp->st_info = STT_NOTYPE; symp->st_other = 0; symp->st_shndx = sym->n_sect; symp->st_value = sym->n_value + dt_module_slide(); symp->st_size = 0; if (sym->n_type & N_STAB) { /* Detect C++ methods */ switch(sym->n_type) { case N_FUN: symp->st_info = GELF_ST_INFO((STB_GLOBAL), (STT_FUNC)); break; case N_GSYM: symp->st_info = GELF_ST_INFO((STB_GLOBAL), (STT_OBJECT)); break; default: break; } } else if ((N_ABS | N_EXT) == (sym->n_type & (N_TYPE | N_EXT)) || (N_SECT | N_EXT) == (sym->n_type & (N_TYPE | N_EXT))) { symp->st_info = GELF_ST_INFO((STB_GLOBAL), (sym->n_desc)); } else if ((N_UNDF | N_EXT) == (sym->n_type & (N_TYPE | N_EXT)) && sym->n_sect == NO_SECT) { symp->st_info = GELF_ST_INFO((STB_GLOBAL), (STT_OBJECT)); /* Common */ } return symp; } } return (NULL); }