static void profile_create(hrtime_t interval, const char *name, int kind) { profile_probe_t *prof; int nr_frames = PROF_ARTIFICIAL_FRAMES + dtrace_mach_aframes(); if (profile_aframes) nr_frames = profile_aframes; if (interval < profile_interval_min) return; if (dtrace_probe_lookup(profile_id, NULL, NULL, name) != 0) return; atomic_inc_32(&profile_total); if (profile_total > profile_max) { atomic_dec_32(&profile_total); return; } prof = kmem_zalloc(sizeof (profile_probe_t), KM_SLEEP); (void) strcpy(prof->prof_name, name); prof->prof_interval = interval; prof->prof_cyclic = CYCLIC_NONE; prof->prof_kind = kind; prof->prof_id = dtrace_probe_create(profile_id, NULL, NULL, name, nr_frames, prof); }
static void profile_create(hrtime_t interval, const char *name, int kind) { profile_probe_t *prof; if (interval < profile_interval_min) return; if (dtrace_probe_lookup(profile_id, NULL, NULL, name) != 0) return; atomic_add_32(&profile_total, 1); if (profile_total > profile_max) { atomic_add_32(&profile_total, -1); return; } if (PROF_TICK == kind) prof = kmem_zalloc(sizeof (profile_probe_t), KM_SLEEP); else prof = kmem_zalloc(sizeof (profile_probe_t) + NCPU*sizeof(profile_probe_percpu_t), KM_SLEEP); (void) strlcpy(prof->prof_name, name, sizeof(prof->prof_name)); prof->prof_interval = interval; prof->prof_cyclic = CYCLIC_NONE; prof->prof_kind = kind; prof->prof_id = dtrace_probe_create(profile_id, NULL, NULL, name, profile_aframes ? profile_aframes : PROF_ARTIFICIAL_FRAMES, prof); }
/*ARGSUSED*/ static void machtrace_provide(void *arg, const dtrace_probedesc_t *desc) { #pragma unused(arg) /* __APPLE__ */ int i; if (desc != NULL) return; machtrace_init(mach_trap_table, &machtrace_sysent); for (i = 0; i < NSYSCALL; i++) { if (machtrace_sysent[i].stsy_underlying == NULL) continue; if (dtrace_probe_lookup(machtrace_id, NULL, mach_syscall_name_table[i], "entry") != 0) continue; (void) dtrace_probe_create(machtrace_id, NULL, mach_syscall_name_table[i], "entry", MACHTRACE_ARTIFICIAL_FRAMES, (void *)((uintptr_t)SYSTRACE_ENTRY(i))); (void) dtrace_probe_create(machtrace_id, NULL, mach_syscall_name_table[i], "return", MACHTRACE_ARTIFICIAL_FRAMES, (void *)((uintptr_t)SYSTRACE_RETURN(i))); machtrace_sysent[i].stsy_entry = DTRACE_IDNONE; machtrace_sysent[i].stsy_return = DTRACE_IDNONE; } }
static void sdt_create_probe(struct sdt_probe *probe) { struct sdt_provider *prov; char mod[DTRACE_MODNAMELEN]; char func[DTRACE_FUNCNAMELEN]; char name[DTRACE_NAMELEN]; const char *from; char *to; size_t len; if (probe->version != (int)sizeof(*probe)) { printf("ignoring probe %p, version %u expected %u\n", probe, probe->version, (int)sizeof(*probe)); return; } TAILQ_FOREACH(prov, &sdt_prov_list, prov_entry) if (strcmp(prov->name, probe->prov->name) == 0) break; KASSERT(prov != NULL, ("probe defined without a provider")); /* If no module name was specified, use the module filename. */ if (*probe->mod == 0) { len = strlcpy(mod, probe->sdtp_lf->filename, sizeof(mod)); if (len > 3 && strcmp(mod + len - 3, ".ko") == 0) mod[len - 3] = '\0'; } else strlcpy(mod, probe->mod, sizeof(mod)); /* * Unfortunately this is necessary because the Solaris DTrace * code mixes consts and non-consts with casts to override * the incompatibilies. On FreeBSD, we use strict warnings * in the C compiler, so we have to respect const vs non-const. */ strlcpy(func, probe->func, sizeof(func)); if (func[0] == '\0') strcpy(func, "none"); from = probe->name; to = name; for (len = 0; len < (sizeof(name) - 1) && *from != '\0'; len++, from++, to++) { if (from[0] == '_' && from[1] == '_') { *to = '-'; from++; } else *to = *from; } *to = '\0'; if (dtrace_probe_lookup(prov->id, mod, func, name) != DTRACE_IDNONE) return; (void)dtrace_probe_create(prov->id, mod, func, name, 1, probe); }
void dt_perf_provide(void *arg, const dtrace_probedesc_t *desc) { if (dtrace_probe_lookup(dt_perf_id, "dt_perf", NULL, "invoke") != 0) return; invoke_pid = dtrace_probe_create(dt_perf_id, "dt_perf", NULL, "invoke", 0, NULL); result_pid = dtrace_probe_create(dt_perf_id, "dt_perf", NULL, "result", 0, NULL); }
/*ARGSUSED*/ static void lockstat_provide(void *arg, const dtrace_probedesc_t *desc) { int i = 0; for (i = 0; lockstat_probes[i].lsp_func != NULL; i++) { lockstat_probe_t *probe = &lockstat_probes[i]; if (dtrace_probe_lookup(lockstat_id, "genunix", probe->lsp_func, probe->lsp_name) != 0) continue; ASSERT(!probe->lsp_id); probe->lsp_id = dtrace_probe_create(lockstat_id, "genunix", probe->lsp_func, probe->lsp_name, 1, probe); } }
/*ARGSUSED*/ static void lockstat_provide(void *arg, const dtrace_probedesc_t *desc) { #pragma unused(arg, desc) /* __APPLE__ */ int i = 0; for (i = 0; lockstat_probes[i].lsp_func != NULL; i++) { lockstat_probe_t *probe = &lockstat_probes[i]; if (dtrace_probe_lookup(lockstat_id, "mach_kernel", probe->lsp_func, probe->lsp_name) != 0) continue; ASSERT(!probe->lsp_id); probe->lsp_id = dtrace_probe_create(lockstat_id, "mach_kernel", probe->lsp_func, probe->lsp_name, LOCKSTAT_AFRAMES, probe); } }
static void systrace_provide(void *arg, dtrace_probedesc_t *desc) { int i; if (desc != NULL) return; for (i = 0; i < MAXSYSCALL; i++) { if (dtrace_probe_lookup(systrace_id, MODNAME, uglyhack.pp_syscallnames[i], "entry") != 0) continue; (void) dtrace_probe_create(systrace_id, MODNAME, uglyhack.pp_syscallnames[i], "entry", SYSTRACE_ARTIFICIAL_FRAMES, (void *)((uintptr_t)SYSTRACE_ENTRY(i))); (void) dtrace_probe_create(systrace_id, MODNAME, uglyhack.pp_syscallnames[i], "return", SYSTRACE_ARTIFICIAL_FRAMES, (void *)((uintptr_t)SYSTRACE_RETURN(i))); } }
static void systrace_provide(void *arg, const dtrace_probedesc_t *desc) { int i; if (desc != NULL) return; for (i = 0; i < MAXSYSCALL; i++) { if (dtrace_probe_lookup(systrace_id, NULL, SYSCALLNAMES[i], "entry") != 0) continue; (void) dtrace_probe_create(systrace_id, NULL, SYSCALLNAMES[i], "entry", SYSTRACE_ARTIFICIAL_FRAMES, (void *)(intptr_t)SYSTRACE_ENTRY(i)); (void) dtrace_probe_create(systrace_id, NULL, SYSCALLNAMES[i], "return", SYSTRACE_ARTIFICIAL_FRAMES, (void *)(intptr_t)SYSTRACE_RETURN(i)); } }
/*ARGSUSED*/ static void systrace_provide(void *arg, const dtrace_probedesc_t *desc) { #pragma unused(arg) /* __APPLE__ */ int i; if (desc != NULL) return; systrace_init(sysent, &systrace_sysent); #ifdef _SYSCALL32_IMPL systrace_init(sysent32, &systrace_sysent32); #endif for (i = 0; i < NSYSCALL; i++) { if (systrace_sysent[i].stsy_underlying == NULL) continue; if (dtrace_probe_lookup(systrace_id, NULL, syscallnames[i], "entry") != 0) continue; (void) dtrace_probe_create(systrace_id, NULL, syscallnames[i], "entry", SYSTRACE_ARTIFICIAL_FRAMES, (void *)((uintptr_t)SYSTRACE_ENTRY(i))); (void) dtrace_probe_create(systrace_id, NULL, syscallnames[i], "return", SYSTRACE_ARTIFICIAL_FRAMES, (void *)((uintptr_t)SYSTRACE_RETURN(i))); systrace_sysent[i].stsy_entry = DTRACE_IDNONE; systrace_sysent[i].stsy_return = DTRACE_IDNONE; #ifdef _SYSCALL32_IMPL systrace_sysent32[i].stsy_entry = DTRACE_IDNONE; systrace_sysent32[i].stsy_return = DTRACE_IDNONE; #endif } }
static void dtnfsclient_provide(void *arg, dtrace_probedesc_t *desc) { int i; if (desc != NULL) return; /* * Register access cache probes. */ if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str, dtnfsclient_flush_str, dtnfsclient_done_str) == 0) { nfsclient_accesscache_flush_done_id = dtrace_probe_create( dtnfsclient_id, dtnfsclient_accesscache_str, dtnfsclient_flush_str, dtnfsclient_done_str, 0, NULL); } if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str, dtnfsclient_get_str, dtnfsclient_hit_str) == 0) { nfsclient_accesscache_get_hit_id = dtrace_probe_create( dtnfsclient_id, dtnfsclient_accesscache_str, dtnfsclient_get_str, dtnfsclient_hit_str, 0, NULL); } if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str, dtnfsclient_get_str, dtnfsclient_miss_str) == 0) { nfsclient_accesscache_get_miss_id = dtrace_probe_create( dtnfsclient_id, dtnfsclient_accesscache_str, dtnfsclient_get_str, dtnfsclient_miss_str, 0, NULL); } if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str, dtnfsclient_load_str, dtnfsclient_done_str) == 0) { nfsclient_accesscache_load_done_id = dtrace_probe_create( dtnfsclient_id, dtnfsclient_accesscache_str, dtnfsclient_load_str, dtnfsclient_done_str, 0, NULL); } /* * Register attribute cache probes. */ if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str, dtnfsclient_flush_str, dtnfsclient_done_str) == 0) { nfsclient_attrcache_flush_done_id = dtrace_probe_create( dtnfsclient_id, dtnfsclient_attrcache_str, dtnfsclient_flush_str, dtnfsclient_done_str, 0, NULL); } if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str, dtnfsclient_get_str, dtnfsclient_hit_str) == 0) { nfsclient_attrcache_get_hit_id = dtrace_probe_create( dtnfsclient_id, dtnfsclient_attrcache_str, dtnfsclient_get_str, dtnfsclient_hit_str, 0, NULL); } if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str, dtnfsclient_get_str, dtnfsclient_miss_str) == 0) { nfsclient_attrcache_get_miss_id = dtrace_probe_create( dtnfsclient_id, dtnfsclient_attrcache_str, dtnfsclient_get_str, dtnfsclient_miss_str, 0, NULL); } if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str, dtnfsclient_load_str, dtnfsclient_done_str) == 0) { nfsclient_attrcache_load_done_id = dtrace_probe_create( dtnfsclient_id, dtnfsclient_attrcache_str, dtnfsclient_load_str, dtnfsclient_done_str, 0, NULL); } /* * Register NFSv2 RPC procedures; note sparseness check for each slot * in the NFSv3 procnum-indexed array. */ for (i = 0; i < NFS_NPROCS; i++) { if (dtnfsclient_rpcs[i].nr_v2_name != NULL && dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs2_str, dtnfsclient_rpcs[i].nr_v2_name, dtnfsclient_start_str) == 0) { dtnfsclient_rpcs[i].nr_v2_id_start = dtrace_probe_create(dtnfsclient_id, dtnfsclient_nfs2_str, dtnfsclient_rpcs[i].nr_v2_name, dtnfsclient_start_str, 0, &nfsclient_nfs2_start_probes[i]); } if (dtnfsclient_rpcs[i].nr_v2_name != NULL && dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs2_str, dtnfsclient_rpcs[i].nr_v2_name, dtnfsclient_done_str) == 0) { dtnfsclient_rpcs[i].nr_v2_id_done = dtrace_probe_create(dtnfsclient_id, dtnfsclient_nfs2_str, dtnfsclient_rpcs[i].nr_v2_name, dtnfsclient_done_str, 0, &nfsclient_nfs2_done_probes[i]); } } /* * Register NFSv3 RPC procedures. */ for (i = 0; i < NFS_NPROCS; i++) { if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs3_str, dtnfsclient_rpcs[i].nr_v3_name, dtnfsclient_start_str) == 0) { dtnfsclient_rpcs[i].nr_v3_id_start = dtrace_probe_create(dtnfsclient_id, dtnfsclient_nfs3_str, dtnfsclient_rpcs[i].nr_v3_name, dtnfsclient_start_str, 0, &nfsclient_nfs3_start_probes[i]); } if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs3_str, dtnfsclient_rpcs[i].nr_v3_name, dtnfsclient_done_str) == 0) { dtnfsclient_rpcs[i].nr_v3_id_done = dtrace_probe_create(dtnfsclient_id, dtnfsclient_nfs3_str, dtnfsclient_rpcs[i].nr_v3_name, dtnfsclient_done_str, 0, &nfsclient_nfs3_done_probes[i]); } } }
/*ARGSUSED*/ static void __sdt_provide_module(void *arg, struct modctl *ctl) { #pragma unused(arg) struct module *mp = (struct module *)ctl->mod_address; char *modname = ctl->mod_modname; sdt_probedesc_t *sdpd; sdt_probe_t *sdp, *old; sdt_provider_t *prov; int len; /* * One for all, and all for one: if we haven't yet registered all of * our providers, we'll refuse to provide anything. */ for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) { if (prov->sdtp_id == DTRACE_PROVNONE) return; } if (!mp || mp->sdt_nprobes != 0 || (sdpd = mp->sdt_probes) == NULL) return; for (sdpd = mp->sdt_probes; sdpd != NULL; sdpd = sdpd->sdpd_next) { const char *name = sdpd->sdpd_name, *func; char *nname; int i, j; dtrace_id_t id; for (prov = sdt_providers; prov->sdtp_prefix != NULL; prov++) { const char *prefpart, *prefix = prov->sdtp_prefix; if ((prefpart = strstr(name, prefix))) { name = prefpart + strlen(prefix); break; } } nname = kmem_alloc(len = strlen(name) + 1, KM_SLEEP); for (i = 0, j = 0; name[j] != '\0'; i++) { if (name[j] == '_' && name[j + 1] == '_') { nname[i] = '-'; j += 2; } else { nname[i] = name[j++]; } } nname[i] = '\0'; sdp = kmem_zalloc(sizeof (sdt_probe_t), KM_SLEEP); sdp->sdp_loadcnt = ctl->mod_loadcnt; sdp->sdp_ctl = ctl; sdp->sdp_name = nname; sdp->sdp_namelen = len; sdp->sdp_provider = prov; func = sdpd->sdpd_func; if (func == NULL) func = "<unknown>"; /* * We have our provider. Now create the probe. */ if ((id = dtrace_probe_lookup(prov->sdtp_id, modname, func, nname)) != DTRACE_IDNONE) { old = dtrace_probe_arg(prov->sdtp_id, id); ASSERT(old != NULL); sdp->sdp_next = old->sdp_next; sdp->sdp_id = id; old->sdp_next = sdp; } else { sdp->sdp_id = dtrace_probe_create(prov->sdtp_id, modname, func, nname, SDT_AFRAMES, sdp); mp->sdt_nprobes++; } #if 0 printf ("__sdt_provide_module: sdpd=0x%p sdp=0x%p name=%s, id=%d\n", sdpd, sdp, nname, sdp->sdp_id); #endif sdp->sdp_hashnext = sdt_probetab[SDT_ADDR2NDX(sdpd->sdpd_offset)]; sdt_probetab[SDT_ADDR2NDX(sdpd->sdpd_offset)] = sdp; sdp->sdp_patchval = SDT_PATCHVAL; sdp->sdp_patchpoint = (sdt_instr_t *)sdpd->sdpd_offset; sdp->sdp_savedval = *sdp->sdp_patchpoint; } }
/** * @callback_method_impl{dtrace_pops_t,dtps_provide} */ static void vboxDtPOps_Provide(void *pvProv, const dtrace_probedesc_t *pDtProbeDesc) { PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv; AssertPtrReturnVoid(pProv); LOG_DTRACE(("%s: %p / %p pDtProbeDesc=%p\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, pDtProbeDesc)); if (pDtProbeDesc) return; /* We don't generate probes, so never mind these requests. */ if (pProv->TracerData.DTrace.fZombie) return; dtrace_provider_id_t const idProvider = pProv->TracerData.DTrace.idProvider; AssertPtrReturnVoid(idProvider); AssertPtrReturnVoid(pProv->pHdr); AssertReturnVoid(pProv->pHdr->offProbeLocs != 0); uint32_t const cProbeLocs = pProv->pHdr->cbProbeLocs / sizeof(VTGPROBELOC); /* Need a buffer for extracting the function names and mangling them in case of collision. */ size_t const cbFnNmBuf = _4K + _1K; char *pszFnNmBuf = (char *)RTMemAlloc(cbFnNmBuf); if (!pszFnNmBuf) return; /* * Itereate the probe location list and register all probes related to * this provider. */ uint16_t const idxProv = (uint16_t)((PVTGDESCPROVIDER)((uintptr_t)pProv->pHdr + pProv->pHdr->offProviders) - pProv->pDesc); uint32_t idxProbeLoc; for (idxProbeLoc = 0; idxProbeLoc < cProbeLocs; idxProbeLoc++) { /* Skip probe location belonging to other providers or once that we've already reported. */ PCVTGPROBELOC pProbeLocRO = &pProv->paProbeLocsRO[idxProbeLoc]; PVTGDESCPROBE pProbeDesc = pProbeLocRO->pProbe; if (pProbeDesc->idxProvider != idxProv) continue; uint32_t *pidProbe; if (!pProv->fUmod) pidProbe = (uint32_t *)&pProbeLocRO->idProbe; else pidProbe = &pProv->paR0ProbeLocs[idxProbeLoc].idProbe; if (*pidProbe != 0) continue; /* The function name may need to be stripped since we're using C++ compilers for most of the code. ASSUMES nobody are brave/stupid enough to use function pointer returns without typedef'ing properly them (e.g. signal). */ const char *pszPrbName = vboxDtVtgGetString(pProv->pHdr, pProbeDesc->offName); const char *pszFunc = pProbeLocRO->pszFunction; const char *psz = strchr(pProbeLocRO->pszFunction, '('); size_t cch; if (psz) { /* skip blanks preceeding the parameter parenthesis. */ while ( (uintptr_t)psz > (uintptr_t)pProbeLocRO->pszFunction && RT_C_IS_BLANK(psz[-1])) psz--; /* Find the start of the function name. */ pszFunc = psz - 1; while ((uintptr_t)pszFunc > (uintptr_t)pProbeLocRO->pszFunction) { char ch = pszFunc[-1]; if (!RT_C_IS_ALNUM(ch) && ch != '_' && ch != ':') break; pszFunc--; } cch = psz - pszFunc; } else cch = strlen(pszFunc); RTStrCopyEx(pszFnNmBuf, cbFnNmBuf, pszFunc, cch); /* Look up the probe, if we have one in the same function, mangle the function name a little to avoid having to deal with having multiple location entries with the same probe ID. (lazy bird) */ Assert(!*pidProbe); if (dtrace_probe_lookup(idProvider, pProv->pszModName, pszFnNmBuf, pszPrbName) != DTRACE_IDNONE) { RTStrPrintf(pszFnNmBuf+cch, cbFnNmBuf - cch, "-%u", pProbeLocRO->uLine); if (dtrace_probe_lookup(idProvider, pProv->pszModName, pszFnNmBuf, pszPrbName) != DTRACE_IDNONE) { unsigned iOrd = 2; while (iOrd < 128) { RTStrPrintf(pszFnNmBuf+cch, cbFnNmBuf - cch, "-%u-%u", pProbeLocRO->uLine, iOrd); if (dtrace_probe_lookup(idProvider, pProv->pszModName, pszFnNmBuf, pszPrbName) == DTRACE_IDNONE) break; iOrd++; } if (iOrd >= 128) { LogRel(("VBoxDrv: More than 128 duplicate probe location instances %s at line %u in function %s [%s], probe %s\n", pProbeLocRO->uLine, pProbeLocRO->pszFunction, pszFnNmBuf, pszPrbName)); continue; } } } /* Create the probe. */ AssertCompile(sizeof(*pidProbe) == sizeof(dtrace_id_t)); *pidProbe = dtrace_probe_create(idProvider, pProv->pszModName, pszFnNmBuf, pszPrbName, 1 /*aframes*/, (void *)(uintptr_t)idxProbeLoc); pProv->TracerData.DTrace.cProvidedProbes++; } RTMemFree(pszFnNmBuf); LOG_DTRACE(("%s: returns\n", __FUNCTION__)); }
/*ARGSUSED*/ static void sdt_provide_module(void *arg, struct modctl *ctl) { # if defined(sun) struct module *mp = ctl->mod_mp; char *modname = ctl->mod_modname; sdt_probedesc_t *sdpd; sdt_probe_t *sdp, *old; sdt_provider_t *prov; /* * One for all, and all for one: if we haven't yet registered all of * our providers, we'll refuse to provide anything. */ for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) { if (prov->sdtp_id == DTRACE_PROVNONE) return; } if (mp->sdt_nprobes != 0 || (sdpd = mp->sdt_probes) == NULL) return; for (sdpd = mp->sdt_probes; sdpd != NULL; sdpd = sdpd->sdpd_next) { char *name = sdpd->sdpd_name, *func, *nname; int i, j, len; sdt_provider_t *prov; ulong_t offs; dtrace_id_t id; for (prov = sdt_providers; prov->sdtp_prefix != NULL; prov++) { char *prefix = prov->sdtp_prefix; if (strncmp(name, prefix, strlen(prefix)) == 0) { name += strlen(prefix); break; } } nname = kmem_alloc(len = strlen(name) + 1, KM_SLEEP); for (i = 0, j = 0; name[j] != '\0'; i++) { if (name[j] == '_' && name[j + 1] == '_') { nname[i] = '-'; j += 2; } else { nname[i] = name[j++]; } } nname[i] = '\0'; sdp = kmem_zalloc(sizeof (sdt_probe_t), KM_SLEEP); sdp->sdp_loadcnt = ctl->mod_loadcnt; sdp->sdp_ctl = ctl; sdp->sdp_name = nname; sdp->sdp_namelen = len; sdp->sdp_provider = prov; func = kobj_searchsym(mp, sdpd->sdpd_offset, &offs); if (func == NULL) func = "<unknown>"; /* * We have our provider. Now create the probe. */ if ((id = dtrace_probe_lookup(prov->sdtp_id, modname, func, nname)) != DTRACE_IDNONE) { old = dtrace_probe_arg(prov->sdtp_id, id); ASSERT(old != NULL); sdp->sdp_next = old->sdp_next; sdp->sdp_id = id; old->sdp_next = sdp; } else { sdp->sdp_id = dtrace_probe_create(prov->sdtp_id, modname, func, nname, 3, sdp); mp->sdt_nprobes++; } sdp->sdp_hashnext = sdt_probetab[SDT_ADDR2NDX(sdpd->sdpd_offset)]; sdt_probetab[SDT_ADDR2NDX(sdpd->sdpd_offset)] = sdp; sdp->sdp_patchval = SDT_PATCHVAL; sdp->sdp_patchpoint = (uint8_t *)sdpd->sdpd_offset; sdp->sdp_savedval = *sdp->sdp_patchpoint; } # endif }
/*ARGSUSED*/ static void sdt_provide_module(void *arg, struct modctl *ctl) { struct module *mp = ctl->mod_mp; char *modname = ctl->mod_modname; int primary, nprobes = 0; sdt_probedesc_t *sdpd; sdt_probe_t *sdp, *old; uint32_t *tab; sdt_provider_t *prov; int len; /* * One for all, and all for one: if we haven't yet registered all of * our providers, we'll refuse to provide anything. */ for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) { if (prov->sdtp_id == DTRACE_PROVNONE) return; } if (mp->sdt_nprobes != 0 || (sdpd = mp->sdt_probes) == NULL) return; kobj_textwin_alloc(mp); /* * Hack to identify unix/genunix/krtld. */ primary = vmem_contains(heap_arena, (void *)ctl, sizeof (struct modctl)) == 0; /* * If there hasn't been an sdt table allocated, we'll do so now. */ if (mp->sdt_tab == NULL) { for (; sdpd != NULL; sdpd = sdpd->sdpd_next) { nprobes++; } /* * We could (should?) determine precisely the size of the * table -- but a reasonable maximum will suffice. */ mp->sdt_size = nprobes * SDT_ENTRY_SIZE; mp->sdt_tab = kobj_texthole_alloc(mp->text, mp->sdt_size); if (mp->sdt_tab == NULL) { cmn_err(CE_WARN, "couldn't allocate SDT table " "for module %s", modname); return; } } tab = (uint32_t *)mp->sdt_tab; for (sdpd = mp->sdt_probes; sdpd != NULL; sdpd = sdpd->sdpd_next) { char *name = sdpd->sdpd_name, *func, *nname; int i, j; sdt_provider_t *prov; ulong_t offs; dtrace_id_t id; for (prov = sdt_providers; prov->sdtp_prefix != NULL; prov++) { char *prefix = prov->sdtp_prefix; if (strncmp(name, prefix, strlen(prefix)) == 0) { name += strlen(prefix); break; } } nname = kmem_alloc(len = strlen(name) + 1, KM_SLEEP); for (i = 0, j = 0; name[j] != '\0'; i++) { if (name[j] == '_' && name[j + 1] == '_') { nname[i] = '-'; j += 2; } else { nname[i] = name[j++]; } } nname[i] = '\0'; sdp = kmem_zalloc(sizeof (sdt_probe_t), KM_SLEEP); sdp->sdp_loadcnt = ctl->mod_loadcnt; sdp->sdp_primary = primary; sdp->sdp_ctl = ctl; sdp->sdp_name = nname; sdp->sdp_namelen = len; sdp->sdp_provider = prov; func = kobj_searchsym(mp, sdpd->sdpd_offset + (uintptr_t)mp->text, &offs); if (func == NULL) func = "<unknown>"; /* * We have our provider. Now create the probe. */ if ((id = dtrace_probe_lookup(prov->sdtp_id, modname, func, nname)) != DTRACE_IDNONE) { old = dtrace_probe_arg(prov->sdtp_id, id); ASSERT(old != NULL); sdp->sdp_next = old->sdp_next; sdp->sdp_id = id; old->sdp_next = sdp; } else { sdp->sdp_id = dtrace_probe_create(prov->sdtp_id, modname, func, nname, 1, sdp); mp->sdt_nprobes++; } sdp->sdp_patchval = SDT_CALL((uintptr_t)mp->text + sdpd->sdpd_offset, tab); sdp->sdp_patchpoint = (uint32_t *)((uintptr_t)mp->textwin + sdpd->sdpd_offset); sdp->sdp_savedval = *sdp->sdp_patchpoint; sdt_initialize(sdp, &tab); } }
void sdt_provide_module(void *arg, struct module *mp) { char *modname = mp->name; dtrace_mprovider_t *prov; sdt_probedesc_t *sdpd; sdt_probe_t *sdp, *prv; int idx, len; /* * Nothing to do if the module SDT probes were already created. */ if (PDATA(mp)->sdt_probe_cnt != 0) return; /* * Nothing to do if there are no SDT probes. */ if (mp->sdt_probec == 0) return; /* * Do not provide any probes unless all SDT providers have been created * for this meta-provider. */ for (prov = sdt_providers; prov->dtmp_name != NULL; prov++) { if (prov->dtmp_id == DTRACE_PROVNONE) return; } if (!sdt_provide_module_arch(arg, mp)) return; for (idx = 0, sdpd = mp->sdt_probes; idx < mp->sdt_probec; idx++, sdpd++) { char *name = sdpd->sdpd_name, *nname; int i, j; dtrace_mprovider_t *prov; dtrace_id_t id; for (prov = sdt_providers; prov->dtmp_pref != NULL; prov++) { char *prefix = prov->dtmp_pref; int len = strlen(prefix); if (strncmp(name, prefix, len) == 0) { name += len; break; } } nname = kmalloc(len = strlen(name) + 1, GFP_KERNEL); if (nname == NULL) { pr_warn("Unable to create probe %s: out-of-memory\n", name); continue; } for (i = j = 0; name[j] != '\0'; i++) { if (name[j] == '_' && name[j + 1] == '_') { nname[i] = '-'; j += 2; } else nname[i] = name[j++]; } nname[i] = '\0'; sdp = kzalloc(sizeof(sdt_probe_t), GFP_KERNEL); if (sdp == NULL) { pr_warn("Unable to create probe %s: out-of-memory\n", nname); continue; } sdp->sdp_loadcnt = 1; /* FIXME */ sdp->sdp_module = mp; sdp->sdp_name = nname; sdp->sdp_namelen = len; sdp->sdp_provider = prov; if ((id = dtrace_probe_lookup(prov->dtmp_id, modname, sdpd->sdpd_func, nname)) != DTRACE_IDNONE) { prv = dtrace_probe_arg(prov->dtmp_id, id); ASSERT(prv != NULL); sdp->sdp_next = prv->sdp_next; sdp->sdp_id = id; prv->sdp_next = sdp; } else { sdp->sdp_id = dtrace_probe_create(prov->dtmp_id, modname, sdpd->sdpd_func, nname, SDT_AFRAMES, sdp); PDATA(mp)->sdt_probe_cnt++; } sdp->sdp_hashnext = sdt_probetab[ SDT_ADDR2NDX(sdpd->sdpd_offset)]; sdt_probetab[SDT_ADDR2NDX(sdpd->sdpd_offset)] = sdp; sdp->sdp_patchpoint = (asm_instr_t *)sdpd->sdpd_offset; sdt_provide_probe_arch(sdp, mp, idx); } }