static void dt_proc_bpdestroy(dt_proc_t *dpr, int delbkpts) { #if defined(sun) int state = Pstate(dpr->dpr_proc); #else int state = proc_state(dpr->dpr_proc); #endif dt_bkpt_t *dbp, *nbp; assert(DT_MUTEX_HELD(&dpr->dpr_lock)); for (dbp = dt_list_next(&dpr->dpr_bps); dbp != NULL; dbp = nbp) { printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); #ifdef DOODAD if (delbkpts && dbp->dbp_active && state != PS_LOST && state != PS_UNDEAD) { (void) Pdelbkpt(dpr->dpr_proc, dbp->dbp_addr, dbp->dbp_instr); } #endif nbp = dt_list_next(dbp); dt_list_delete(&dpr->dpr_bps, dbp); dt_free(dpr->dpr_hdl, dbp); } }
static void dt_proc_bpmatch(dtrace_hdl_t *dtp, dt_proc_t *dpr) { const lwpstatus_t *psp = &Pstatus(dpr->dpr_proc)->pr_lwp; dt_bkpt_t *dbp; assert(DT_MUTEX_HELD(&dpr->dpr_lock)); for (dbp = dt_list_next(&dpr->dpr_bps); dbp != NULL; dbp = dt_list_next(dbp)) { if (psp->pr_reg[R_PC] == dbp->dbp_addr) break; } if (dbp == NULL) { dt_dprintf("pid %d: spurious breakpoint wakeup for %lx\n", (int)dpr->dpr_pid, (ulong_t)psp->pr_reg[R_PC]); return; } dt_dprintf("pid %d: hit breakpoint at %lx (%lu)\n", (int)dpr->dpr_pid, (ulong_t)dbp->dbp_addr, ++dbp->dbp_hits); dbp->dbp_func(dtp, dpr, dbp->dbp_data); (void) Pxecbkpt(dpr->dpr_proc, dbp->dbp_instr); }
/* * Unload all the loaded modules and then refresh the module cache with the * latest list of loaded modules and their address ranges. */ void dtrace_update(dtrace_hdl_t *dtp) { dt_module_t *dmp; DIR *dirp; for (dmp = dt_list_next(&dtp->dt_modlist); dmp != NULL; dmp = dt_list_next(dmp)) dt_module_unload(dtp, dmp); if (!(dtp->dt_oflags & DTRACE_O_NOSYS)) { dt_module_update(dtp, "mach_kernel"); } /* * Look up all the macro identifiers and set di_id to the latest value. * This code collaborates with dt_lex.l on the use of di_id. We will * need to implement something fancier if we need to support non-ints. */ dt_idhash_lookup(dtp->dt_macros, "egid")->di_id = getegid(); dt_idhash_lookup(dtp->dt_macros, "euid")->di_id = geteuid(); dt_idhash_lookup(dtp->dt_macros, "gid")->di_id = getgid(); dt_idhash_lookup(dtp->dt_macros, "pid")->di_id = getpid(); dt_idhash_lookup(dtp->dt_macros, "pgid")->di_id = getpgid(0); dt_idhash_lookup(dtp->dt_macros, "ppid")->di_id = getppid(); dt_idhash_lookup(dtp->dt_macros, "projid")->di_id = getprojid(); dt_idhash_lookup(dtp->dt_macros, "sid")->di_id = getsid(0); dt_idhash_lookup(dtp->dt_macros, "taskid")->di_id = gettaskid(); dt_idhash_lookup(dtp->dt_macros, "uid")->di_id = getuid(); /* * Cache the pointers to the modules representing the base executable * and the run-time linker in the dtrace client handle. Note that on * x86 krtld is folded into unix, so if we don't find it, use unix * instead. */ dtp->dt_exec = dt_module_lookup_by_name(dtp, "mach_kernel"); dtp->dt_rtld = dt_module_lookup_by_name(dtp, "dyld"); /* XXX to what purpose? */ /* * If this is the first time we are initializing the module list, * remove the module for genunix from the module list and then move it * to the front of the module list. We do this so that type and symbol * queries encounter genunix and thereby optimize for the common case * in dtrace_lookup_by_name() and dtrace_lookup_by_type(), below. */ if (dtp->dt_exec != NULL && dtp->dt_cdefs == NULL && dtp->dt_ddefs == NULL) { dt_list_delete(&dtp->dt_modlist, dtp->dt_exec); dt_list_prepend(&dtp->dt_modlist, dtp->dt_exec); } }
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_object_iter(dtrace_hdl_t *dtp, dtrace_obj_f *func, void *data) { const dt_module_t *dmp = dt_list_next(&dtp->dt_modlist); dtrace_objinfo_t dto; int rv; for (; dmp != NULL; dmp = dt_list_next(dmp)) { if ((rv = (*func)(dtp, dt_module_info(dmp, &dto), data)) != 0) return (rv); } return (0); }
static void dt_proc_bpdisable(dt_proc_t *dpr) { dt_bkpt_t *dbp; assert(DT_MUTEX_HELD(&dpr->dpr_lock)); for (dbp = dt_list_next(&dpr->dpr_bps); dbp != NULL; dbp = dt_list_next(dbp)) { if (dbp->dbp_active && Pdelbkpt(dpr->dpr_proc, dbp->dbp_addr, dbp->dbp_instr) == 0) dbp->dbp_active = B_FALSE; } dt_dprintf("breakpoints disabled\n"); }
/* * Exported interface to look up a symbol by address. We return the GElf_Sym * and complete symbol information for the matching symbol. */ int dtrace_lookup_by_addr(dtrace_hdl_t *dtp, GElf_Addr addr, GElf_Sym *symp, dtrace_syminfo_t *sip) { dt_module_t *dmp; uint_t id; const dtrace_vector_t *v = dtp->dt_vector; if (v != NULL) return (v->dtv_lookup_by_addr(dtp->dt_varg, addr, symp, sip)); for (dmp = dt_list_next(&dtp->dt_modlist); dmp != NULL; dmp = dt_list_next(dmp)) { if (addr - dmp->dm_text_va < dmp->dm_text_size || addr - dmp->dm_data_va < dmp->dm_data_size || addr - dmp->dm_bss_va < dmp->dm_bss_size) break; } if (dmp == NULL) return (dt_set_errno(dtp, EDT_NOSYMADDR)); if (dt_module_load(dtp, dmp) == -1) return (-1); /* dt_errno is set for us */ if (symp != NULL) { if (dmp->dm_ops->do_symaddr(dmp, addr, symp, &id) == NULL) return (dt_set_errno(dtp, EDT_NOSYMADDR)); } if (sip != NULL) { sip->dts_object = dmp->dm_name; if (symp != NULL) { sip->dts_name = (const char *) dmp->dm_strtab.cts_data + symp->st_name; sip->dts_id = id; } else { sip->dts_name = NULL; sip->dts_id = 0; } } return (0); }
static void dt_proc_bpdisable(dt_proc_t *dpr) { dt_bkpt_t *dbp; assert(DT_MUTEX_HELD(&dpr->dpr_lock)); for (dbp = dt_list_next(&dpr->dpr_bps); dbp != NULL; dbp = dt_list_next(dbp)) { printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); #ifdef DOODAD if (dbp->dbp_active && Pdelbkpt(dpr->dpr_proc, dbp->dbp_addr, dbp->dbp_instr) == 0) dbp->dbp_active = B_FALSE; #endif } dt_dprintf("breakpoints disabled\n"); }
void dt_program_destroy(dtrace_hdl_t *dtp, dtrace_prog_t *pgp) { dt_stmt_t *stp, *next; uint_t i; for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) { next = dt_list_next(stp); dtrace_stmt_destroy(dtp, stp->ds_desc); dt_free(dtp, stp); } for (i = 0; i < pgp->dp_xrefslen; i++) dt_free(dtp, pgp->dp_xrefs[i]); dt_free(dtp, pgp->dp_xrefs); dt_list_delete(&dtp->dt_programs, pgp); dt_free(dtp, pgp); }
static void dt_proc_bpdestroy(dt_proc_t *dpr, int delbkpts) { int state = Pstate(dpr->dpr_proc); dt_bkpt_t *dbp, *nbp; assert(DT_MUTEX_HELD(&dpr->dpr_lock)); for (dbp = dt_list_next(&dpr->dpr_bps); dbp != NULL; dbp = nbp) { if (delbkpts && dbp->dbp_active && state != PS_LOST && state != PS_UNDEAD) { (void) Pdelbkpt(dpr->dpr_proc, dbp->dbp_addr, dbp->dbp_instr); } nbp = dt_list_next(dbp); dt_list_delete(&dpr->dpr_bps, dbp); dt_free(dpr->dpr_hdl, dbp); } }
void dt_proc_hash_destroy(dtrace_hdl_t *dtp) { dt_proc_hash_t *dph = dtp->dt_procs; dt_proc_t *dpr; while ((dpr = dt_list_next(&dph->dph_lrulist)) != NULL) dt_proc_destroy(dtp, dpr->dpr_proc); dtp->dt_procs = NULL; dt_free(dtp, dph); }
static void dt_pragma_depends_finddep(dtrace_hdl_t *dtp, const char *lname, char *lib, size_t len) { dt_dirpath_t *dirp; struct stat sbuf; int found = 0; for (dirp = dt_list_next(&dtp->dt_lib_path); dirp != NULL; dirp = dt_list_next(dirp)) { (void) snprintf(lib, len, "%s/%s", dirp->dir_path, lname); if (stat(lib, &sbuf) == 0) { found = 1; break; } } if (!found) xyerror(D_PRAGMA_DEPEND, "failed to find dependency in libpath: %s", lname); }
static void dt_proc_bpmatch(dtrace_hdl_t *dtp, dt_proc_t *dpr) { #ifdef illumos const lwpstatus_t *psp = &Pstatus(dpr->dpr_proc)->pr_lwp; #else unsigned long pc; #endif dt_bkpt_t *dbp; assert(DT_MUTEX_HELD(&dpr->dpr_lock)); #ifndef illumos proc_regget(dpr->dpr_proc, REG_PC, &pc); proc_bkptregadj(&pc); #endif for (dbp = dt_list_next(&dpr->dpr_bps); dbp != NULL; dbp = dt_list_next(dbp)) { #ifdef illumos if (psp->pr_reg[R_PC] == dbp->dbp_addr) break; #else if (pc == dbp->dbp_addr) break; #endif } if (dbp == NULL) { dt_dprintf("pid %d: spurious breakpoint wakeup for %lx\n", #ifdef illumos (int)dpr->dpr_pid, (ulong_t)psp->pr_reg[R_PC]); #else (int)dpr->dpr_pid, pc); #endif return; }
/*ARGSUSED*/ static int dt_opt_syslibdir(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) { dt_dirpath_t *dp = dt_list_next(&dtp->dt_lib_path); char *path; if (arg == NULL) return (dt_set_errno(dtp, EDT_BADOPTVAL)); if ((path = strdup(arg)) == NULL) return (dt_set_errno(dtp, EDT_NOMEM)); free(dp->dir_path); dp->dir_path = path; return (0); }
int dtrace_handle_err(dtrace_hdl_t *dtp, dtrace_handle_err_f *hdlr, void *arg) { dtrace_prog_t *pgp = NULL; dt_stmt_t *stp; dtrace_ecbdesc_t *edp; /* * We don't currently support multiple error handlers. */ if (dtp->dt_errhdlr != NULL) return (dt_set_errno(dtp, EALREADY)); /* * If the DTRACEOPT_GRABANON is enabled, the anonymous enabling will * already have a dtrace:::ERROR probe enabled; save 'hdlr' and 'arg' * but do not bother compiling and enabling _dt_errprog. */ if (dtp->dt_options[DTRACEOPT_GRABANON] != DTRACEOPT_UNSET) goto out; if ((pgp = dtrace_program_strcompile(dtp, _dt_errprog, DTRACE_PROBESPEC_NAME, DTRACE_C_ZDEFS, 0, NULL)) == NULL) return (dt_set_errno(dtp, dtrace_errno(dtp))); stp = dt_list_next(&pgp->dp_stmts); assert(stp != NULL); edp = stp->ds_desc->dtsd_ecbdesc; assert(edp != NULL); edp->dted_uarg = DT_ECB_ERROR; out: dtp->dt_errhdlr = hdlr; dtp->dt_errarg = arg; dtp->dt_errprog = pgp; return (0); }
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)); } }
/* * Unload all the loaded modules and then refresh the module cache with the * latest list of loaded modules and their address ranges. */ void dtrace_update(dtrace_hdl_t *dtp) { dt_module_t *dmp; DIR *dirp; #if defined(__FreeBSD__) int fileid; #endif for (dmp = dt_list_next(&dtp->dt_modlist); dmp != NULL; dmp = dt_list_next(dmp)) dt_module_unload(dtp, dmp); #if defined(sun) /* * Open /system/object and attempt to create a libdtrace module for * each kernel module that is loaded on the current system. */ if (!(dtp->dt_oflags & DTRACE_O_NOSYS) && (dirp = opendir(OBJFS_ROOT)) != NULL) { struct dirent *dp; while ((dp = readdir(dirp)) != NULL) { if (dp->d_name[0] != '.') dt_module_update(dtp, dp->d_name); } (void) closedir(dirp); } #elif defined(__FreeBSD__) /* * Use FreeBSD's kernel loader interface to discover what kernel * modules are loaded and create a libdtrace module for each one. */ for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) { struct kld_file_stat k_stat; k_stat.version = sizeof(k_stat); if (kldstat(fileid, &k_stat) == 0) dt_module_update(dtp, &k_stat); } #endif /* * Look up all the macro identifiers and set di_id to the latest value. * This code collaborates with dt_lex.l on the use of di_id. We will * need to implement something fancier if we need to support non-ints. */ dt_idhash_lookup(dtp->dt_macros, "egid")->di_id = getegid(); dt_idhash_lookup(dtp->dt_macros, "euid")->di_id = geteuid(); dt_idhash_lookup(dtp->dt_macros, "gid")->di_id = getgid(); dt_idhash_lookup(dtp->dt_macros, "pid")->di_id = getpid(); dt_idhash_lookup(dtp->dt_macros, "pgid")->di_id = getpgid(0); dt_idhash_lookup(dtp->dt_macros, "ppid")->di_id = getppid(); #if defined(sun) dt_idhash_lookup(dtp->dt_macros, "projid")->di_id = getprojid(); #endif dt_idhash_lookup(dtp->dt_macros, "sid")->di_id = getsid(0); #if defined(sun) dt_idhash_lookup(dtp->dt_macros, "taskid")->di_id = gettaskid(); #endif dt_idhash_lookup(dtp->dt_macros, "uid")->di_id = getuid(); /* * Cache the pointers to the modules representing the base executable * and the run-time linker in the dtrace client handle. Note that on * x86 krtld is folded into unix, so if we don't find it, use unix * instead. */ dtp->dt_exec = dt_module_lookup_by_name(dtp, "genunix"); dtp->dt_rtld = dt_module_lookup_by_name(dtp, "krtld"); if (dtp->dt_rtld == NULL) dtp->dt_rtld = dt_module_lookup_by_name(dtp, "unix"); /* * If this is the first time we are initializing the module list, * remove the module for genunix from the module list and then move it * to the front of the module list. We do this so that type and symbol * queries encounter genunix and thereby optimize for the common case * in dtrace_lookup_by_name() and dtrace_lookup_by_type(), below. */ if (dtp->dt_exec != NULL && dtp->dt_cdefs == NULL && dtp->dt_ddefs == NULL) { dt_list_delete(&dtp->dt_modlist, dtp->dt_exec); dt_list_prepend(&dtp->dt_modlist, dtp->dt_exec); } }
/*ARGSUSED*/ void dtrace_program_info(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_proginfo_t *pip) { dt_stmt_t *stp; dtrace_actdesc_t *ap; dtrace_ecbdesc_t *last = NULL; if (pip == NULL) return; bzero(pip, sizeof (dtrace_proginfo_t)); if (dt_list_next(&pgp->dp_stmts) != NULL) { pip->dpi_descattr = _dtrace_maxattr; pip->dpi_stmtattr = _dtrace_maxattr; } else { pip->dpi_descattr = _dtrace_defattr; pip->dpi_stmtattr = _dtrace_defattr; } for (stp = dt_list_next(&pgp->dp_stmts); stp; stp = dt_list_next(stp)) { dtrace_ecbdesc_t *edp = stp->ds_desc->dtsd_ecbdesc; if (edp == last) continue; last = edp; pip->dpi_descattr = dt_attr_min(stp->ds_desc->dtsd_descattr, pip->dpi_descattr); pip->dpi_stmtattr = dt_attr_min(stp->ds_desc->dtsd_stmtattr, pip->dpi_stmtattr); /* * If there aren't any actions, account for the fact that * recording the epid will generate a record. */ if (edp->dted_action == NULL) pip->dpi_recgens++; for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) { if (ap->dtad_kind == DTRACEACT_SPECULATE) { pip->dpi_speculations++; continue; } if (DTRACEACT_ISAGG(ap->dtad_kind)) { pip->dpi_recgens -= ap->dtad_arg; pip->dpi_aggregates++; continue; } if (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind)) continue; if (ap->dtad_kind == DTRACEACT_DIFEXPR && ap->dtad_difo->dtdo_rtype.dtdt_kind == DIF_TYPE_CTF && ap->dtad_difo->dtdo_rtype.dtdt_size == 0) continue; pip->dpi_recgens++; } } }
/* * Pop the topmost PCB from the PCB stack and destroy any data structures that * are associated with it. If 'err' is non-zero, destroy any intermediate * state that is left behind as part of a compilation that has failed. */ void dt_pcb_pop(dtrace_hdl_t *dtp, int err) { dt_pcb_t *pcb = yypcb; uint_t i; assert(pcb != NULL); assert(pcb == dtp->dt_pcb); while (pcb->pcb_dstack.ds_next != NULL) (void) dt_scope_pop(); dt_scope_destroy(&pcb->pcb_dstack); dt_irlist_destroy(&pcb->pcb_ir); dt_node_link_free(&pcb->pcb_list); dt_node_link_free(&pcb->pcb_hold); if (err != 0) { dt_xlator_t *dxp, *nxp; dt_provider_t *pvp, *nvp; if (pcb->pcb_prog != NULL) dt_program_destroy(dtp, pcb->pcb_prog); if (pcb->pcb_stmt != NULL) dtrace_stmt_destroy(dtp, pcb->pcb_stmt); if (pcb->pcb_ecbdesc != NULL) dt_ecbdesc_release(dtp, pcb->pcb_ecbdesc); for (dxp = dt_list_next(&dtp->dt_xlators); dxp; dxp = nxp) { nxp = dt_list_next(dxp); if (dxp->dx_gen == dtp->dt_gen) dt_xlator_destroy(dtp, dxp); } for (pvp = dt_list_next(&dtp->dt_provlist); pvp; pvp = nvp) { nvp = dt_list_next(pvp); if (pvp->pv_gen == dtp->dt_gen) dt_provider_destroy(dtp, pvp); } (void) dt_idhash_iter(dtp->dt_aggs, dt_pcb_pop_ident, dtp); dt_idhash_update(dtp->dt_aggs); (void) dt_idhash_iter(dtp->dt_globals, dt_pcb_pop_ident, dtp); dt_idhash_update(dtp->dt_globals); (void) dt_idhash_iter(dtp->dt_tls, dt_pcb_pop_ident, dtp); dt_idhash_update(dtp->dt_tls); (void) ctf_discard(dtp->dt_cdefs->dm_ctfp); (void) ctf_discard(dtp->dt_ddefs->dm_ctfp); } if (pcb->pcb_pragmas != NULL) dt_idhash_destroy(pcb->pcb_pragmas); if (pcb->pcb_locals != NULL) dt_idhash_destroy(pcb->pcb_locals); if (pcb->pcb_idents != NULL) dt_idhash_destroy(pcb->pcb_idents); if (pcb->pcb_inttab != NULL) dt_inttab_destroy(pcb->pcb_inttab); if (pcb->pcb_strtab != NULL) dt_strtab_destroy(pcb->pcb_strtab); if (pcb->pcb_regs != NULL) dt_regset_destroy(pcb->pcb_regs); for (i = 0; i < pcb->pcb_asxreflen; i++) dt_free(dtp, pcb->pcb_asxrefs[i]); dt_free(dtp, pcb->pcb_asxrefs); dt_difo_free(dtp, pcb->pcb_difo); free(pcb->pcb_filetag); free(pcb->pcb_sflagv); dtp->dt_pcb = pcb->pcb_prev; bzero(pcb, sizeof (dt_pcb_t)); yyinit(dtp->dt_pcb); }
/* * Exported interface to look up a symbol by name. We return the GElf_Sym and * complete symbol information for the matching symbol. */ int dtrace_lookup_by_name(dtrace_hdl_t *dtp, const char *object, const char *name, GElf_Sym *symp, dtrace_syminfo_t *sip) { dt_module_t *dmp; dt_ident_t *idp; uint_t n, id; GElf_Sym sym; uint_t mask = 0; /* mask of dt_module flags to match */ uint_t bits = 0; /* flag bits that must be present */ if (object != DTRACE_OBJ_EVERY && object != DTRACE_OBJ_KMODS && object != DTRACE_OBJ_UMODS) { if ((dmp = dt_module_from_object(dtp, object)) == NULL) return (-1); /* dt_errno is set for us */ if (dt_module_load(dtp, dmp) == -1) return (-1); /* dt_errno is set for us */ n = 1; } else { if (object == DTRACE_OBJ_KMODS) mask = bits = DT_DM_KERNEL; else if (object == DTRACE_OBJ_UMODS) mask = DT_DM_KERNEL; dmp = dt_list_next(&dtp->dt_modlist); n = dtp->dt_nmods; } if (symp == NULL) symp = &sym; for (; n > 0; n--, dmp = dt_list_next(dmp)) { if ((dmp->dm_flags & mask) != bits) continue; /* failed to match required attributes */ if (dt_module_load(dtp, dmp) == -1) continue; /* failed to load symbol table */ if (dmp->dm_ops->do_symname(dmp, name, symp, &id) != NULL) { if (sip != NULL) { sip->dts_object = dmp->dm_name; sip->dts_name = (const char *) dmp->dm_strtab.cts_data + symp->st_name; sip->dts_id = id; } return (0); } if (dmp->dm_extern != NULL && (idp = dt_idhash_lookup(dmp->dm_extern, name)) != NULL) { if (symp != &sym) { symp->st_name = (uintptr_t)idp->di_name; symp->st_info = GELF_ST_INFO(STB_GLOBAL, STT_NOTYPE); symp->st_other = 0; symp->st_shndx = SHN_UNDEF; symp->st_value = 0; symp->st_size = ctf_type_size(idp->di_ctfp, idp->di_type); } if (sip != NULL) { sip->dts_object = dmp->dm_name; sip->dts_name = idp->di_name; sip->dts_id = idp->di_id; } return (0); } } return (dt_set_errno(dtp, EDT_NOSYM)); }
int dtrace_lookup_by_type(dtrace_hdl_t *dtp, const char *object, const char *name, dtrace_typeinfo_t *tip) { dtrace_typeinfo_t ti; dt_module_t *dmp; int found = 0; ctf_id_t id; uint_t n, i; int justone; ctf_file_t *fp; char *buf, *p, *q; uint_t mask = 0; /* mask of dt_module flags to match */ uint_t bits = 0; /* flag bits that must be present */ if (object != DTRACE_OBJ_EVERY && object != DTRACE_OBJ_KMODS && object != DTRACE_OBJ_UMODS) { if ((dmp = dt_module_from_object(dtp, object)) == NULL) return (-1); /* dt_errno is set for us */ if (dt_module_load(dtp, dmp) == -1) return (-1); /* dt_errno is set for us */ n = 1; justone = 1; } else { if (object == DTRACE_OBJ_KMODS) mask = bits = DT_DM_KERNEL; else if (object == DTRACE_OBJ_UMODS) mask = DT_DM_KERNEL; dmp = dt_list_next(&dtp->dt_modlist); n = dtp->dt_nmods; justone = 0; } if (tip == NULL) tip = &ti; for (; n > 0; n--, dmp = dt_list_next(dmp)) { if ((dmp->dm_flags & mask) != bits) continue; /* failed to match required attributes */ /* * If we can't load the CTF container, continue on to the next * module. If our search was scoped to only one module then * return immediately leaving dt_errno unmodified. */ if (dt_module_hasctf(dtp, dmp) == 0) { if (justone) return (-1); continue; } /* * Look up the type in the module's CTF container. If our * match is a forward declaration tag, save this choice in * 'tip' and keep going in the hope that we will locate the * underlying structure definition. Otherwise just return. */ if (dmp->dm_pid == 0) { id = ctf_lookup_by_name(dmp->dm_ctfp, name); fp = dmp->dm_ctfp; } else { if ((p = strchr(name, '`')) != NULL) { buf = strdup(name); if (buf == NULL) return (dt_set_errno(dtp, EDT_NOMEM)); p = strchr(buf, '`'); if ((q = strchr(p + 1, '`')) != NULL) p = q; *p = '\0'; fp = dt_module_getctflib(dtp, dmp, buf); if (fp == NULL || (id = ctf_lookup_by_name(fp, p + 1)) == CTF_ERR) id = CTF_ERR; free(buf); } else { for (i = 0; i < dmp->dm_nctflibs; i++) { fp = dmp->dm_libctfp[i]; id = ctf_lookup_by_name(fp, name); if (id != CTF_ERR) break; } } } if (id != CTF_ERR) { tip->dtt_object = dmp->dm_name; tip->dtt_ctfp = fp; tip->dtt_type = id; if (ctf_type_kind(fp, ctf_type_resolve(fp, id)) != CTF_K_FORWARD) return (0); found++; } } if (found == 0) return (dt_set_errno(dtp, EDT_NOTYPE)); return (0); }
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)); }
void * dtrace_dof_create(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t flags) { dt_dof_t *ddo = &dtp->dt_dof; const dtrace_ecbdesc_t *edp, *last; const dtrace_probedesc_t *pdp; const dtrace_actdesc_t *ap; const dt_stmt_t *stp; uint_t maxacts = 0; uint_t maxfmt = 0; dt_provider_t *pvp; dt_xlator_t *dxp; dof_actdesc_t *dofa; dof_sec_t *sp; size_t ssize, lsize; dof_hdr_t h; dt_buf_t dof; char *fmt; uint_t i; if (flags & ~DTRACE_D_MASK) { (void) dt_set_errno(dtp, EINVAL); return (NULL); } flags |= dtp->dt_dflags; if (dof_hdr(dtp, pgp->dp_dofversion, &h) != 0) return (NULL); if (dt_dof_reset(dtp, pgp) != 0) return (NULL); /* * Iterate through the statement list computing the maximum number of * actions and the maximum format string for allocating local buffers. */ for (last = NULL, stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = dt_list_next(stp), last = edp) { dtrace_stmtdesc_t *sdp = stp->ds_desc; dtrace_actdesc_t *ap = sdp->dtsd_action; if (sdp->dtsd_fmtdata != NULL) { i = VBDTCAST(uint_t)dtrace_printf_format(dtp, sdp->dtsd_fmtdata, NULL, 0); maxfmt = MAX(maxfmt, i); } if ((edp = sdp->dtsd_ecbdesc) == last) continue; /* same ecb as previous statement */ for (i = 0, ap = edp->dted_action; ap; ap = ap->dtad_next) i++; maxacts = MAX(maxacts, i); } dofa = alloca(sizeof (dof_actdesc_t) * maxacts); fmt = alloca(maxfmt + 1); ddo->ddo_strsec = dof_add_lsect(ddo, NULL, DOF_SECT_STRTAB, 1, 0, 0, 0); (void) dof_add_string(ddo, ""); /* * If there are references to dynamic translators in the program, add * an imported translator table entry for each referenced translator. */ if (pgp->dp_xrefslen != 0) { for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL; dxp = dt_list_next(dxp)) { if (dxp->dx_id < pgp->dp_xrefslen && pgp->dp_xrefs[dxp->dx_id] != NULL) dof_add_translator(ddo, dxp, DOF_SECT_XLIMPORT); } } /* * Now iterate through the statement list, creating the DOF section * headers and data for each one and adding them to our buffers. */ for (last = NULL, stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = dt_list_next(stp), last = edp) { dof_secidx_t probesec = DOF_SECIDX_NONE; dof_secidx_t prdsec = DOF_SECIDX_NONE; dof_secidx_t actsec = DOF_SECIDX_NONE; const dt_stmt_t *next = stp; dtrace_stmtdesc_t *sdp = stp->ds_desc; dof_stridx_t strndx = 0; dof_probedesc_t dofp; dof_ecbdesc_t dofe; uint_t i; if ((edp = stp->ds_desc->dtsd_ecbdesc) == last) continue; /* same ecb as previous statement */ pdp = &edp->dted_probe; /* * Add a DOF_SECT_PROBEDESC for the ECB's probe description, * and copy the probe description strings into the string table. */ dofp.dofp_strtab = ddo->ddo_strsec; dofp.dofp_provider = dof_add_string(ddo, pdp->dtpd_provider); dofp.dofp_mod = dof_add_string(ddo, pdp->dtpd_mod); dofp.dofp_func = dof_add_string(ddo, pdp->dtpd_func); dofp.dofp_name = dof_add_string(ddo, pdp->dtpd_name); dofp.dofp_id = pdp->dtpd_id; probesec = dof_add_lsect(ddo, &dofp, DOF_SECT_PROBEDESC, sizeof (dof_secidx_t), 0, sizeof (dof_probedesc_t), sizeof (dof_probedesc_t)); /* * If there is a predicate DIFO associated with the ecbdesc, * write out the DIFO sections and save the DIFO section index. */ if (edp->dted_pred.dtpdd_difo != NULL) prdsec = dof_add_difo(ddo, edp->dted_pred.dtpdd_difo); /* * Now iterate through the action list generating DIFOs as * referenced therein and adding action descriptions to 'dofa'. */ for (i = 0, ap = edp->dted_action; ap != NULL; ap = ap->dtad_next, i++) { if (ap->dtad_difo != NULL) { dofa[i].dofa_difo = dof_add_difo(ddo, ap->dtad_difo); } else dofa[i].dofa_difo = DOF_SECIDX_NONE; /* * If the first action in a statement has format data, * add the format string to the global string table. */ if (sdp != NULL && ap == sdp->dtsd_action) { if (sdp->dtsd_fmtdata != NULL) { (void) dtrace_printf_format(dtp, sdp->dtsd_fmtdata, fmt, maxfmt + 1); strndx = dof_add_string(ddo, fmt); } else strndx = 0; /* use dtad_arg instead */ if ((next = dt_list_next(next)) != NULL) sdp = next->ds_desc; else sdp = NULL; } if (strndx != 0) { dofa[i].dofa_arg = strndx; dofa[i].dofa_strtab = ddo->ddo_strsec; } else { dofa[i].dofa_arg = ap->dtad_arg; dofa[i].dofa_strtab = DOF_SECIDX_NONE; } dofa[i].dofa_kind = ap->dtad_kind; dofa[i].dofa_ntuple = ap->dtad_ntuple; dofa[i].dofa_uarg = ap->dtad_uarg; } if (i > 0) { actsec = dof_add_lsect(ddo, dofa, DOF_SECT_ACTDESC, sizeof (uint64_t), 0, sizeof (dof_actdesc_t), sizeof (dof_actdesc_t) * i); } /* * Now finally, add the DOF_SECT_ECBDESC referencing all the * previously created sub-sections. */ dofe.dofe_probes = probesec; dofe.dofe_pred = prdsec; dofe.dofe_actions = actsec; dofe.dofe_pad = 0; dofe.dofe_uarg = edp->dted_uarg; (void) dof_add_lsect(ddo, &dofe, DOF_SECT_ECBDESC, sizeof (uint64_t), 0, 0, sizeof (dof_ecbdesc_t)); } /* * If any providers are user-defined, output DOF sections corresponding * to the providers and the probes and arguments that they define. */ if (flags & DTRACE_D_PROBES) { for (pvp = dt_list_next(&dtp->dt_provlist); pvp != NULL; pvp = dt_list_next(pvp)) dof_add_provider(ddo, pvp); } /* * If we're not stripping unloadable sections, generate compiler * comments and any other unloadable miscellany. */ if (!(flags & DTRACE_D_STRIP)) { (void) dof_add_usect(ddo, _dtrace_version, DOF_SECT_COMMENTS, sizeof (char), 0, 0, strlen(_dtrace_version) + 1); #ifndef VBOX (void) dof_add_usect(ddo, &dtp->dt_uts, DOF_SECT_UTSNAME, sizeof (char), 0, 0, sizeof (struct utsname)); #endif } /* * Compute and fill in the appropriate values for the dof_hdr_t's * dofh_secnum, dofh_loadsz, and dofh_filez values. */ h.dofh_secnum = ddo->ddo_nsecs; ssize = sizeof (h) + dt_buf_len(&ddo->ddo_secs); h.dofh_loadsz = ssize + dt_buf_len(&ddo->ddo_ldata) + dt_buf_len(&ddo->ddo_strs); if (dt_buf_len(&ddo->ddo_udata) != 0) { lsize = roundup(h.dofh_loadsz, sizeof (uint64_t)); h.dofh_filesz = lsize + dt_buf_len(&ddo->ddo_udata); } else { lsize = h.dofh_loadsz; h.dofh_filesz = lsize; } /* * Set the global DOF_SECT_STRTAB's offset to be after the header, * section headers, and other loadable data. Since we're going to * iterate over the buffer data directly, we must check for errors. */ if ((i = dt_buf_error(&ddo->ddo_secs)) != 0) { (void) dt_set_errno(dtp, i); return (NULL); } sp = dt_buf_ptr(&ddo->ddo_secs); assert(sp[ddo->ddo_strsec].dofs_type == DOF_SECT_STRTAB); assert(ssize == sizeof (h) + sizeof (dof_sec_t) * ddo->ddo_nsecs); sp[ddo->ddo_strsec].dofs_offset = ssize + dt_buf_len(&ddo->ddo_ldata); sp[ddo->ddo_strsec].dofs_size = dt_buf_len(&ddo->ddo_strs); /* * Now relocate all the other section headers by adding the appropriate * delta to their respective dofs_offset values. */ for (i = 0; i < ddo->ddo_nsecs; i++, sp++) { if (i == ddo->ddo_strsec) continue; /* already relocated above */ if (sp->dofs_flags & DOF_SECF_LOAD) sp->dofs_offset += ssize; else sp->dofs_offset += lsize; } /* * Finally, assemble the complete in-memory DOF buffer by writing the * header and then concatenating all our buffers. dt_buf_concat() will * propagate any errors and cause dt_buf_claim() to return NULL. */ dt_buf_create(dtp, &dof, "dof", h.dofh_filesz); dt_buf_write(dtp, &dof, &h, sizeof (h), sizeof (uint64_t)); dt_buf_concat(dtp, &dof, &ddo->ddo_secs, sizeof (uint64_t)); dt_buf_concat(dtp, &dof, &ddo->ddo_ldata, sizeof (uint64_t)); dt_buf_concat(dtp, &dof, &ddo->ddo_strs, sizeof (char)); dt_buf_concat(dtp, &dof, &ddo->ddo_udata, sizeof (uint64_t)); return (dt_buf_claim(dtp, &dof)); }