/* * 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); } }
/* * The #pragma depends_on directive can be used to express a dependency on a * module, provider or library which if not present will cause processing to * abort. */ static void dt_pragma_depends(const char *prname, dt_node_t *cnp) { dtrace_hdl_t *dtp = yypcb->pcb_hdl; dt_node_t *nnp = cnp ? cnp->dn_list : NULL; int found; dt_lib_depend_t *dld; if (cnp == NULL || nnp == NULL || cnp->dn_kind != DT_NODE_IDENT || nnp->dn_kind != DT_NODE_IDENT) { xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s " "<class> <name>\n", prname); } if (strcmp(cnp->dn_string, "provider") == 0) found = dt_provider_lookup(dtp, nnp->dn_string) != NULL; else if (strcmp(cnp->dn_string, "module") == 0) { dt_module_t *mp = dt_module_lookup_by_name(dtp, nnp->dn_string); found = mp != NULL && dt_module_getctf(dtp, mp) != NULL; } else if (strcmp(cnp->dn_string, "library") == 0) { /* * We have the file we are working on in dtp->dt_filetag * so find that node and add the dependency in. */ if (yypcb->pcb_cflags & DTRACE_C_CTL) { char lib[MAXPATHLEN]; dld = dt_lib_depend_lookup(&dtp->dt_lib_dep, dtp->dt_filetag); assert(dld != NULL); (void) snprintf(lib, MAXPATHLEN, "%s%s", dld->dtld_libpath, nnp->dn_string); if ((dt_lib_depend_add(dtp, &dld->dtld_dependencies, lib)) != 0) { xyerror(D_PRAGMA_DEPEND, "failed to add dependency %s:%s\n", lib, dtrace_errmsg(dtp, dtrace_errno(dtp))); } } found = 1; } else { xyerror(D_PRAGMA_INVAL, "invalid class %s " "specified by #pragma %s\n", cnp->dn_string, prname); } if (!found) { xyerror(D_PRAGMA_DEPEND, "program requires %s %s\n", cnp->dn_string, nnp->dn_string); } }
int dtrace_symbol_type(dtrace_hdl_t *dtp, const GElf_Sym *symp, const dtrace_syminfo_t *sip, dtrace_typeinfo_t *tip) { dt_module_t *dmp; tip->dtt_object = NULL; tip->dtt_ctfp = NULL; tip->dtt_type = CTF_ERR; tip->dtt_flags = 0; if ((dmp = dt_module_lookup_by_name(dtp, sip->dts_object)) == NULL) return (dt_set_errno(dtp, EDT_NOMOD)); if (symp->st_shndx == SHN_UNDEF && dmp->dm_extern != NULL) { dt_ident_t *idp = dt_idhash_lookup(dmp->dm_extern, sip->dts_name); if (idp == NULL) return (dt_set_errno(dtp, EDT_NOSYM)); tip->dtt_ctfp = idp->di_ctfp; tip->dtt_type = idp->di_type; } else if (GELF_ST_TYPE(symp->st_info) != STT_FUNC) { if (dt_module_getctf(dtp, dmp) == NULL) return (-1); /* errno is set for us */ tip->dtt_ctfp = dmp->dm_ctfp; tip->dtt_type = ctf_lookup_by_symbol(dmp->dm_ctfp, sip->dts_id); if (tip->dtt_type == CTF_ERR) { dtp->dt_ctferr = ctf_errno(tip->dtt_ctfp); return (dt_set_errno(dtp, EDT_CTF)); } } else { tip->dtt_ctfp = DT_FPTR_CTFP(dtp); tip->dtt_type = DT_FPTR_TYPE(dtp); } tip->dtt_object = dmp->dm_name; return (0); }
/* * 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); } }
/* * The #pragma depends_on directive can be used to express a dependency on a * module, provider or library which if not present will cause processing to * abort. */ static void dt_pragma_depends(const char *prname, dt_node_t *cnp) { dtrace_hdl_t *dtp = yypcb->pcb_hdl; dt_node_t *nnp = cnp ? cnp->dn_list : NULL; int found; dt_lib_depend_t *dld; char lib[MAXPATHLEN]; size_t plen; char *provs, *cpy, *tok; if (cnp == NULL || nnp == NULL || cnp->dn_kind != DT_NODE_IDENT || nnp->dn_kind != DT_NODE_IDENT) { xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s " "<class> <name>\n", prname); } if (strcmp(cnp->dn_string, "provider") == 0) { /* * First try to get the provider list using the * debug.dtrace.providers sysctl, since that'll work even if * we're not running as root. */ provs = NULL; if (sysctlbyname("debug.dtrace.providers", NULL, &plen, NULL, 0) || ((provs = dt_alloc(dtp, plen)) == NULL) || sysctlbyname("debug.dtrace.providers", provs, &plen, NULL, 0)) found = dt_provider_lookup(dtp, nnp->dn_string) != NULL; else { found = B_FALSE; for (cpy = provs; (tok = strsep(&cpy, " ")) != NULL; ) if (strcmp(tok, nnp->dn_string) == 0) { found = B_TRUE; break; } if (found == B_FALSE) found = dt_provider_lookup(dtp, nnp->dn_string) != NULL; } if (provs != NULL) dt_free(dtp, provs); } else if (strcmp(cnp->dn_string, "module") == 0) { dt_module_t *mp = dt_module_lookup_by_name(dtp, nnp->dn_string); found = mp != NULL && dt_module_getctf(dtp, mp) != NULL; } else if (strcmp(cnp->dn_string, "library") == 0) { if (yypcb->pcb_cflags & DTRACE_C_CTL) { assert(dtp->dt_filetag != NULL); dt_pragma_depends_finddep(dtp, nnp->dn_string, lib, sizeof (lib)); dld = dt_lib_depend_lookup(&dtp->dt_lib_dep, dtp->dt_filetag); assert(dld != NULL); if ((dt_lib_depend_add(dtp, &dld->dtld_dependencies, lib)) != 0) { xyerror(D_PRAGMA_DEPEND, "failed to add dependency %s:%s\n", lib, dtrace_errmsg(dtp, dtrace_errno(dtp))); } } else { /* * By this point we have already performed a topological * sort of the dependencies; we process this directive * as satisfied as long as the dependency was properly * loaded. */ if (dtp->dt_filetag == NULL) xyerror(D_PRAGMA_DEPEND, "main program may " "not explicitly depend on a library"); dld = dt_lib_depend_lookup(&dtp->dt_lib_dep, dtp->dt_filetag); assert(dld != NULL); dt_pragma_depends_finddep(dtp, nnp->dn_string, lib, sizeof (lib)); dld = dt_lib_depend_lookup(&dtp->dt_lib_dep_sorted, lib); assert(dld != NULL); if (!dld->dtld_loaded) xyerror(D_PRAGMA_DEPEND, "program requires " "library \"%s\" which failed to load", lib); } found = B_TRUE; } else { xyerror(D_PRAGMA_INVAL, "invalid class %s " "specified by #pragma %s\n", cnp->dn_string, prname); } if (!found) { xyerror(D_PRAGMA_DEPEND, "program requires %s %s\n", cnp->dn_string, nnp->dn_string); } }