From c8cb41580f6066a00df43e353bd55ac21d9d0c58 Mon Sep 17 00:00:00 2001 From: Kris Van Hees Date: Mon, 5 Dec 2011 15:01:27 -0500 Subject: [PATCH] SDT implementation (core kernel support for providing a list of static probe points for the kernel pseudo-module, dtrace SDT meta-provider support, ...). Also, new script (dtrace_sdt.sh) to extract locations of SDT probe points in the core kernel. Signed-off-by: Kris Van Hees --- dtrace/Kbuild | 2 +- dtrace/dtrace.h | 57 +++- dtrace/dtrace_probe.c | 9 + dtrace/dtrace_state.c | 2 +- dtrace/sdt.h | 7 - dtrace/sdt_dev.c | 154 ++++++++++ dtrace/sdt_impl.h | 94 ++---- dtrace/sdt_mod.c | 673 ++++++------------------------------------ 8 files changed, 338 insertions(+), 660 deletions(-) delete mode 100644 dtrace/sdt.h diff --git a/dtrace/Kbuild b/dtrace/Kbuild index 6ad516f68669..b717dc0b3b41 100644 --- a/dtrace/Kbuild +++ b/dtrace/Kbuild @@ -51,6 +51,6 @@ fasttrap-y := fasttrap_mod.o fasttrap_dev.o fbt-y := fbt_mod.o fbt_dev.o lockstat-y := lockstat_mod.o lockstat_dev.o profile-y := profile_mod.o profile_dev.o -sdt-y := sdt_mod.o sdt_dev.o sdt_subr.o +sdt-y := sdt_mod.o sdt_dev.o systrace-y := systrace_mod.o systrace_dev.o dt_test-y := dt_test_mod.o dt_test_dev.o diff --git a/dtrace/dtrace.h b/dtrace/dtrace.h index 73e2f157d589..76a6e8da68a0 100644 --- a/dtrace/dtrace.h +++ b/dtrace/dtrace.h @@ -2138,7 +2138,7 @@ extern void dtrace_cred2priv(const cred_t *, uint32_t *, uid_t *); \ static int __init name##_init(void) \ { \ - int ret = 0; \ + int ret = 0; \ \ ret = name##_dev_init(); \ if (ret) \ @@ -2164,6 +2164,61 @@ extern void dtrace_cred2priv(const cred_t *, uint32_t *, uid_t *); module_init(name##_init); \ module_exit(name##_exit); +typedef struct dtrace_mprovider { + char *dtmp_name; + char *dtmp_pref; + dtrace_pattr_t *dtmp_attr; + uint32_t dtmp_priv; + dtrace_pops_t *dtmp_pops; + dtrace_provider_id_t dtmp_id; +} dtrace_mprovider_t; + +#define DT_META_PROVIDER_MODULE(name) \ + static int __init name##_init(void) \ + { \ + int ret = 0; \ + dtrace_mprovider_t *prov; \ + \ + ret = name##_dev_init(); \ + if (ret) \ + goto failed; \ + \ + for (prov = name##_providers; prov->dtmp_name != NULL; prov++) {\ + if (dtrace_register(prov->dtmp_name, prov->dtmp_attr, \ + prov->dtmp_priv, NULL, \ + prov->dtmp_pops, prov, \ + &prov->dtmp_id) != 0) \ + pr_warning("Failed to register sdt provider %s",\ + prov->dtmp_name); \ + } \ + \ + return 0; \ + \ + failed: \ + return ret; \ + } \ + \ + static void __exit name##_exit(void) \ + { \ + int ret = 0; \ + dtrace_mprovider_t *prov; \ + \ + for (prov = name##_providers; prov->dtmp_name != NULL; prov++) {\ + if (prov->dtmp_id != DTRACE_PROVNONE) { \ + ret = dtrace_unregister(prov->dtmp_id); \ + if (ret != 0) \ + return; \ + \ + prov->dtmp_id = DTRACE_PROVNONE; \ + } \ + } \ + \ + name##_dev_exit(); \ + } \ + \ + module_init(name##_init); \ + module_exit(name##_exit); + #define dtrace_membar_producer() mb() #define dtrace_membar_consumer() mb() diff --git a/dtrace/dtrace_probe.c b/dtrace/dtrace_probe.c index 771b813c81e1..0cd23e9d83c0 100644 --- a/dtrace/dtrace_probe.c +++ b/dtrace/dtrace_probe.c @@ -32,6 +32,7 @@ #include #include "dtrace.h" +#include "sdt_impl.h" ktime_t dtrace_chill_interval = KTIME_INIT(1, 0); @@ -171,6 +172,14 @@ void dtrace_probe_provide(dtrace_probedesc_t *desc, dtrace_provider_t *prv) do { prv->dtpv_pops.dtps_provide(prv->dtpv_arg, desc); + /* + * In Linux, the kernel proper is not a module and therefore is + * not listed in the list of modules. Since the kernel proper + * can have probe points (and e.g. has a lot of SDT ones), we + * use a pseudo-kernel module to collect them so that there is + * no need for code duplication in handling such probe points. + */ + prv->dtpv_pops.dtps_provide_module(prv->dtpv_arg, dtrace_kmod); #ifdef FIXME /* * This needs work because (so far) I have not found a way to get access to the diff --git a/dtrace/dtrace_state.c b/dtrace/dtrace_state.c index 379772da22ee..35e186a4209b 100644 --- a/dtrace/dtrace_state.c +++ b/dtrace/dtrace_state.c @@ -461,7 +461,7 @@ again: } } #else - state->dts_cred.dcr_visible = DTRACE_CRV_ALLPROC; + state->dts_cred.dcr_visible = DTRACE_CRV_ALLPROC | DTRACE_CRV_KERNEL; state->dts_cred.dcr_action = DTRACE_CRA_ALL; #endif diff --git a/dtrace/sdt.h b/dtrace/sdt.h deleted file mode 100644 index 6ad3c8013398..000000000000 --- a/dtrace/sdt.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _SDT_H_ -#define _SDT_H_ - -extern int sdt_dev_init(void); -extern void sdt_dev_exit(void); - -#endif /* _SDT_H_ */ diff --git a/dtrace/sdt_dev.c b/dtrace/sdt_dev.c index 6a297c2ef578..504e380be171 100644 --- a/dtrace/sdt_dev.c +++ b/dtrace/sdt_dev.c @@ -28,8 +28,149 @@ #include #include #include +#include +#include "dtrace.h" #include "dtrace_dev.h" +#include "sdt_impl.h" + +#define SDT_PATCHVAL 0xf0 +#define SDT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & sdt_probetab_mask) +#define SDT_PROBETAB_SIZE 0x1000 /* 4k entries -- 16K total */ + +static sdt_probe_t **sdt_probetab; +static int sdt_probetab_size; +static int sdt_probetab_mask; + +static int sdt_invop(struct pt_regs *regs) +{ + sdt_probe_t *sdt = sdt_probetab[SDT_ADDR2NDX(regs->ip)]; + + for (; sdt != NULL; sdt = sdt->sdp_hashnext) { + if ((uintptr_t)sdt->sdp_patchpoint == regs->ip) { + dtrace_probe(sdt->sdp_id, regs->di, regs->si, + regs->dx, regs->cx, regs->r8); + return DTRACE_INVOP_NOP; + } + } + + return 0; +} + +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 len; + + /* + * 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; + } + + /* + * Nothing to do if the module SDT probes were already created. + */ + if (mp->sdt_nprobes != 0) + return; + + for (sdpd = mp->sdt_probes; sdpd != NULL; sdpd = sdpd->sdpd_next) { + 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); + + 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); + 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, 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; + } +} + +int sdt_enable(void *arg, dtrace_id_t id, void *parg) +{ + sdt_probe_t *sdp = parg; + + sdt_probe_enable(sdp->sdp_patchpoint); + return 0; +} + +void sdt_disable(void *arg, dtrace_id_t id, void *parg) +{ + sdt_probe_t *sdp = parg; + + sdt_probe_disable(sdp->sdp_patchpoint); +} + +void sdt_getargdesc(void *arg, dtrace_id_t id, void *parg, + dtrace_argdesc_t *desc) +{ +} + +uint64_t sdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, + int aframes) +{ + return 0; +} + +void sdt_destroy(void *arg, dtrace_id_t id, void *parg) +{ +} static long sdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) @@ -70,10 +211,23 @@ int sdt_dev_init(void) pr_err("%s: Can't register misc device %d\n", sdt_dev.name, sdt_dev.minor); + dtrace_register_builtins(); /* FIXME */ + + if (sdt_probetab_size == 0) + sdt_probetab_size = SDT_PROBETAB_SIZE; + + sdt_probetab_mask = sdt_probetab_size - 1; + sdt_probetab = vzalloc(sdt_probetab_size * sizeof(sdt_probe_t *)); + + dtrace_invop_add(sdt_invop); + return ret; } void sdt_dev_exit(void) { + dtrace_invop_remove(sdt_invop); + vfree(sdt_probetab); + misc_deregister(&sdt_dev); } diff --git a/dtrace/sdt_impl.h b/dtrace/sdt_impl.h index 823cdf180e59..31a7788b13a9 100644 --- a/dtrace/sdt_impl.h +++ b/dtrace/sdt_impl.h @@ -1,79 +1,35 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - * - * Copyright 2004, 2011 Oracle, Inc. All rights reserved. - * Use is subject to license terms. - */ +#ifndef _SDT_IMPL_H_ +#define _SDT_IMPL_H_ -#ifndef _SYS_SDT_IMPL_H -#define _SYS_SDT_IMPL_H +#include -#ifdef __cplusplus -extern "C" { -#endif - -#include "dtrace.h" - -#if defined(__i386__) || defined(__x86_64__) -typedef uint8_t sdt_instr_t; -#else -typedef uint32_t sdt_instr_t; -#endif - -typedef struct sdt_provider { - char *sdtp_name; /* name of provider */ - char *sdtp_prefix; /* prefix for probe names */ - dtrace_pattr_t *sdtp_attr; /* stability attributes */ - dtrace_provider_id_t sdtp_id; /* provider ID */ -} sdt_provider_t; - -extern sdt_provider_t sdt_providers[]; /* array of providers */ +extern struct module *dtrace_kmod; typedef struct sdt_probe { - sdt_provider_t *sdp_provider; /* provider */ - char *sdp_name; /* name of probe */ - int sdp_namelen; /* length of allocated name */ - dtrace_id_t sdp_id; /* probe ID */ - struct module *sdp_ctl; /* module ptr */ - int sdp_loadcnt; /* load count for module */ - int sdp_primary; /* non-zero if primary mod */ - sdt_instr_t *sdp_patchpoint; /* patch point */ - sdt_instr_t sdp_patchval; /* instruction to patch */ - sdt_instr_t sdp_savedval; /* saved instruction value */ - struct sdt_probe *sdp_next; /* next probe */ - struct sdt_probe *sdp_hashnext; /* next on hash */ + dtrace_mprovider_t *sdp_provider; /* provider */ + char *sdp_name; /* name of probe */ + int sdp_namelen; /* length of allocated name */ + dtrace_id_t sdp_id; /* probe ID */ + struct module *sdp_module; /* modctl for module */ + int sdp_loadcnt; /* load count for module */ + int sdp_primary; /* non-zero if primary mod */ + sdt_instr_t *sdp_patchpoint;/* patch point */ + sdt_instr_t sdp_patchval; /* instruction to patch */ + sdt_instr_t sdp_savedval; /* saved instruction value */ + struct sdt_probe *sdp_next; /* next probe */ + struct sdt_probe *sdp_hashnext; /* next on hash */ } sdt_probe_t; -typedef struct sdt_argdesc { - const char *sda_provider; /* provider for arg */ - const char *sda_name; /* name of probe */ - const int sda_ndx; /* argument index */ - const int sda_mapping; /* mapping of argument */ - const char *sda_native; /* native type of argument */ - const char *sda_xlate; /* translated type of arg */ -} sdt_argdesc_t; +extern dtrace_mprovider_t sdt_providers[]; +extern void sdt_provide_module(void *, struct module *); +extern int sdt_enable(void *, dtrace_id_t, void *); +extern void sdt_disable(void *, dtrace_id_t, void *); extern void sdt_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *); +extern uint64_t sdt_getarg(void *, dtrace_id_t, void *, int, int); +extern void sdt_destroy(void *, dtrace_id_t, void *); -#ifdef __cplusplus -} -#endif +extern int sdt_dev_init(void); +extern void sdt_dev_exit(void); -#endif /* _SYS_SDT_IMPL_H */ +#endif /* _SDT_IMPL_H_ */ diff --git a/dtrace/sdt_mod.c b/dtrace/sdt_mod.c index 3742b782c530..cbb93d30691f 100644 --- a/dtrace/sdt_mod.c +++ b/dtrace/sdt_mod.c @@ -2,6 +2,7 @@ * FILE: sdt_mod.c * DESCRIPTION: Statically Defined Tracing: module handling * + * * CDDL HEADER START * * The contents of this file are subject to the terms of the @@ -25,473 +26,88 @@ * Use is subject to license terms. */ -#include -#include #include -#include -#include -#include #include "dtrace.h" #include "dtrace_dev.h" -#include "sdt.h" #include "sdt_impl.h" -#define SDT_PATCHVAL 0xf0 -#define SDT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & sdt_probetab_mask) -#define SDT_PROBETAB_SIZE 0x1000 /* 4k entries -- 16K total */ - -///static dev_info_t *sdt_devi; -static int sdt_verbose = 0; -static sdt_probe_t **sdt_probetab; -static int sdt_probetab_size; -static int sdt_probetab_mask; - -struct frame { /* TBD: move to header file, used in dtrace_isa.c also */ - struct frame *fr_savfp; - unsigned long fr_savpc; -} __attribute__((packed)); - -static inline bool mod_loaded(struct module *mod) -{ - return mod->state == MODULE_STATE_LIVE; -} - -static unsigned int mod_loadcnt(struct module *mod) -{ -#ifdef CONFIG_MODULE_UNLOAD - return module_refcount(mod); -#else - return 1; -#endif -} - -#if ELF_CLASS == ELFCLASS32 -typedef Elf32_Sym Sym; -#else -typedef Elf64_Sym Sym; -#endif - -char * -kernel_searchsym(struct module *mp, uintptr_t value, ulong_t *offset) -{ - Sym *symtabptr; - char *strtabptr; - int symnum; - Sym *sym; - Sym *cursym; - uintptr_t curval; - - *offset = (ulong_t)-1l; /* assume not found */ - cursym = NULL; - - if (!within_module_core((unsigned long)value, mp) && - !within_module_init((unsigned long)value, mp)) - return NULL; /* not in this module */ - - strtabptr = NULL; ///FIXME: mp->strings; - symtabptr = (Sym *)mp->symtab; - - /* - * Scan the module's symbol table for a symbol <= value - */ - for (symnum = 1, sym = symtabptr + 1; - symnum < mp->num_symtab; symnum++, sym = (Sym *) - ((uintptr_t)sym /* FIXME: + mp->symhdr->sh_entsize*/)) { - if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL) { - if (ELF_ST_BIND(sym->st_info) != STB_LOCAL) - continue; - if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT && - ELF_ST_TYPE(sym->st_info) != STT_FUNC) - continue; - } - - curval = (uintptr_t)sym->st_value; - - if (curval > value) - continue; - - /* - * If one or both are functions... - */ - if (ELF_ST_TYPE(sym->st_info) == STT_FUNC || (cursym != NULL && - ELF_ST_TYPE(cursym->st_info) == STT_FUNC)) { - /* Ignore if the address is out of the bounds */ - if (value - sym->st_value >= sym->st_size) - continue; - - if (cursym != NULL && - ELF_ST_TYPE(cursym->st_info) == STT_FUNC) { - /* Prefer the function to the non-function */ - if (ELF_ST_TYPE(sym->st_info) != STT_FUNC) - continue; - - /* Prefer the larger of the two functions */ - if (sym->st_size <= cursym->st_size) - continue; - } - } else if (value - curval >= *offset) { - continue; - } - - *offset = (ulong_t)(value - curval); - cursym = sym; - } - if (cursym == NULL) - return (NULL); - - return (strtabptr + cursym->st_name); -} - -static void dtrace_invop_callsite(void) /* TBD: copied from dtrace_isa.c */ -{ -} - -/*ARGSUSED*/ -static int -sdt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax) -{ - uintptr_t stack0, stack1, stack2, stack3, stack4; - int i = 0; - sdt_probe_t *sdt = sdt_probetab[SDT_ADDR2NDX(addr)]; - -#ifdef __x86_64__ - /* - * On amd64, stack[0] contains the dereferenced stack pointer, - * stack[1] contains savfp, stack[2] contains savpc. We want - * to step over these entries. - */ - i += 3; -#endif - - for (; sdt != NULL; sdt = sdt->sdp_hashnext) { - if ((uintptr_t)sdt->sdp_patchpoint == addr) { - /* - * When accessing the arguments on the stack, we must - * protect against accessing beyond the stack. We can - * safely set NOFAULT here -- we know that interrupts - * are already disabled. - */ - DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); - stack0 = stack[i++]; - stack1 = stack[i++]; - stack2 = stack[i++]; - stack3 = stack[i++]; - stack4 = stack[i++]; - DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | - CPU_DTRACE_BADADDR); - - dtrace_probe(sdt->sdp_id, stack0, stack1, - stack2, stack3, stack4); - - return (DTRACE_INVOP_NOP); - } - } - - return (0); -} - -/*ARGSUSED*/ -static void -sdt_provide_module(void *arg, struct module *module) -{ - char *modname = module->name; - 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 (module->sdt_nprobes != 0 || (sdpd = module->sdt_probes) == NULL) - return; - - for (sdpd = module->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 = kmalloc(len = strlen(name) + 1, GFP_KERNEL); - if (!nname) { - pr_warning("sdt cannot allocate memory for module: %s", - module->name); - return; - } - - 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 = kzalloc(sizeof(sdt_probe_t), GFP_KERNEL); - if (!sdp) { - pr_warning("sdt cannot allocate probe for module: %s", - module->name); - kfree(nname); - return; - } -#ifdef CONFIG_MODULE_UNLOAD - sdp->sdp_loadcnt = module_refcount(module); // TBD: not loadcnt -#else - sdp->sdp_loadcnt = 1; -#endif - sdp->sdp_ctl = module; - sdp->sdp_name = nname; - sdp->sdp_namelen = len; - sdp->sdp_provider = prov; - - func = kernel_searchsym(module, sdpd->sdpd_offset, &offs); - - if (func == NULL) - func = ""; - - /* - * 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); - - module->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; - } -} - -/*ARGSUSED*/ -static void -sdt_destroy(void *arg, dtrace_id_t id, void *parg) -{ - sdt_probe_t *sdp = parg, *old, *last, *hash; - struct module *module = sdp->sdp_ctl; - int ndx; - - if (module != NULL && mod_loadcnt(module) == sdp->sdp_loadcnt) { - if ((mod_loadcnt(module) == sdp->sdp_loadcnt && - mod_loaded(module))) { - module->sdt_nprobes--; - } - } - - while (sdp != NULL) { - old = sdp; - - /* - * Now we need to remove this probe from the sdt_probetab. - */ - ndx = SDT_ADDR2NDX(sdp->sdp_patchpoint); - last = NULL; - hash = sdt_probetab[ndx]; - - while (hash != sdp) { - ASSERT(hash != NULL); - last = hash; - hash = hash->sdp_hashnext; - } - - if (last != NULL) { - last->sdp_hashnext = sdp->sdp_hashnext; - } else { - sdt_probetab[ndx] = sdp->sdp_hashnext; - } - - kfree(sdp->sdp_name); - sdp = sdp->sdp_next; - kfree(old); - } -} - -/*ARGSUSED*/ -static int -sdt_enable(void *arg, dtrace_id_t id, void *parg) -{ - sdt_probe_t *sdp = parg; - struct module *module = sdp->sdp_ctl; - - module->mod_nenabled++; - - /* - * If this module has disappeared since we discovered its probes, - * refuse to enable it. - */ - if (!mod_loaded(module)) { - if (sdt_verbose) { - pr_warning( "sdt is failing for probe %s " - "(module %s unloaded)", - sdp->sdp_name, module->name); - } - goto err; - } - - /* - * Now check that our module has the expected load count. If it - * doesn't, this module must have been unloaded and reloaded -- and - * we're not going to touch it. - */ - if (mod_loadcnt(module) != sdp->sdp_loadcnt) { - if (sdt_verbose) { - pr_warning("sdt is failing for probe %s " - "(module %s reloaded)", - sdp->sdp_name, module->name); - } - goto err; - } - - while (sdp != NULL) { - *sdp->sdp_patchpoint = sdp->sdp_patchval; - sdp = sdp->sdp_next; - } -err: - return (0); -} - -/*ARGSUSED*/ -static void -sdt_disable(void *arg, dtrace_id_t id, void *parg) -{ - sdt_probe_t *sdp = parg; - struct module *module = sdp->sdp_ctl; - - module->mod_nenabled--; - - if (!mod_loaded(module) || mod_loadcnt(module) != sdp->sdp_loadcnt) - goto err; - - while (sdp != NULL) { - *sdp->sdp_patchpoint = sdp->sdp_savedval; - sdp = sdp->sdp_next; - } - -err: - ; -} +MODULE_AUTHOR("Kris Van Hees (kris.van.hees@oracle.com)"); +MODULE_DESCRIPTION("Profile Interrupt Tracing"); +MODULE_VERSION("v0.1"); +MODULE_LICENSE("CDDL"); -/*ARGSUSED*/ -uint64_t -sdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, int aframes) -{ - uintptr_t val; - struct frame *fp = (struct frame *)dtrace_getfp(); - uintptr_t *stack; - int i; -#if defined(__x86_64__) - /* - * A total of 6 arguments are passed via registers; any argument with - * index of 5 or lower is therefore in a register. - */ - int inreg = 5; -#endif +static dtrace_pattr_t vtrace_attr = { +{ DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_ISA }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, +{ DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_ISA }, +}; - for (i = 1; i <= aframes; i++) { - fp = (struct frame *)(fp->fr_savfp); +static dtrace_pattr_t info_attr = { +{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, +{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, +}; - if (fp->fr_savpc == (pc_t)dtrace_invop_callsite) { -#if !defined(__x86_64__) - /* - * If we pass through the invalid op handler, we will - * use the pointer that it passed to the stack as the - * second argument to dtrace_invop() as the pointer to - * the stack. - */ - stack = ((uintptr_t **)&fp[1])[1]; -#else - /* - * In the case of amd64, we will use the pointer to the - * regs structure that was pushed when we took the - * trap. To get this structure, we must increment - * beyond the frame structure. If the argument that - * we're seeking is passed on the stack, we'll pull - * the true stack pointer out of the saved registers - * and decrement our argument by the number of - * arguments passed in registers; if the argument - * we're seeking is passed in regsiters, we can just - * load it directly. - */ - struct pt_regs *rp = (struct pt_regs *)((uintptr_t)&fp[1] - + sizeof(uintptr_t)); /* TBD: CHECK */ +static dtrace_pattr_t fc_attr = { +{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, +{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, +}; - if (argno <= inreg) { - stack = (uintptr_t *)&rp->di; - } else { - stack = (uintptr_t *)(rp->sp); - argno -= (inreg + 1); - } -#endif - goto load; - } - } +static dtrace_pattr_t fpu_attr = { +{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, +{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_CPU }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, +}; - /* - * We know that we did not come through a trap to get into - * dtrace_probe() -- the provider simply called dtrace_probe() - * directly. As this is the case, we need to shift the argument - * that we're looking for: the probe ID is the first argument to - * dtrace_probe(), so the argument n will actually be found where - * one would expect to find argument (n + 1). - */ - argno++; +static dtrace_pattr_t fsinfo_attr = { +{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, +{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, +}; -#if defined(__x86_64__) - if (argno <= inreg) { - /* - * This shouldn't happen. If the argument is passed in a - * register then it should have been, well, passed in a - * register... - */ - DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); - return (0); - } +static dtrace_pattr_t stab_attr = { +{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, +{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, +{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, +}; - argno -= (inreg + 1); -#endif - stack = (uintptr_t *)&fp[1]; +static dtrace_pattr_t sdt_attr = { +{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, +}; -load: - DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); - val = stack[argno]; - DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); +static dtrace_pattr_t xpv_attr = { +{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_PLATFORM }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_PLATFORM }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_PLATFORM }, +}; - return (val); -} +static dtrace_pattr_t iscsi_attr = { +{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, +{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, +}; static dtrace_pops_t sdt_pops = { NULL, @@ -503,136 +119,31 @@ static dtrace_pops_t sdt_pops = { sdt_getargdesc, sdt_getarg, NULL, - sdt_destroy + sdt_destroy, }; -#if 0 -/*ARGSUSED*/ -static int -sdt_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) -{ - sdt_provider_t *prov; - - if (ddi_create_minor_node(devi, "sdt", S_IFCHR, - 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { - pr_warning("/dev/sdt couldn't create minor node"); - ddi_remove_minor_node(devi, NULL); - return (DDI_FAILURE); - } - - ddi_report_dev(devi); - ///sdt_devi = devi; - - if (sdt_probetab_size == 0) - sdt_probetab_size = SDT_PROBETAB_SIZE; - - sdt_probetab_mask = sdt_probetab_size - 1; - sdt_probetab = - kzalloc(sdt_probetab_size * sizeof(sdt_probe_t *), GFP_KERNEL); - if (!sdt_probetab) { - pr_warning("sdt cannot allocate/register provider: %s", - prov->sdtp_name); - ddi_remove_minor_node(devi, NULL); - return (DDI_FAILURE); - } - - dtrace_invop_add(sdt_invop); - - for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) { - if (dtrace_register(prov->sdtp_name, prov->sdtp_attr, - DTRACE_PRIV_KERNEL, NULL, - &sdt_pops, prov, &prov->sdtp_id) != 0) { - pr_warning("failed to register sdt provider %s", - prov->sdtp_name); - } - } - - return (DDI_SUCCESS); -} - -/*ARGSUSED*/ -static int -sdt_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) -{ - sdt_provider_t *prov; - - switch (cmd) { - case DDI_DETACH: - break; - - case DDI_SUSPEND: - return (DDI_SUCCESS); - - default: - return (DDI_FAILURE); - } - - for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) { - if (prov->sdtp_id != DTRACE_PROVNONE) { - if (dtrace_unregister(prov->sdtp_id) != 0) - return (DDI_FAILURE); - - prov->sdtp_id = DTRACE_PROVNONE; - } - } - - dtrace_invop_remove(sdt_invop); - kmem_free(sdt_probetab, sdt_probetab_size * sizeof(sdt_probe_t *)); - - return (DDI_SUCCESS); -} - -/*ARGSUSED*/ -static int -sdt_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) -{ - int error; - - switch (infocmd) { - case DDI_INFO_DEVT2DEVINFO: - *result = (void *)sdt_devi; - error = DDI_SUCCESS; - break; - case DDI_INFO_DEVT2INSTANCE: - *result = (void *)0; - error = DDI_SUCCESS; - break; - default: - error = DDI_FAILURE; - } - return (error); -} -#endif - -/*ARGSUSED*/ -static int -sdt_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) -{ - return (0); -} - -#if 0 -int -sdt_init(void) -{ - return 0; -} - -void -sdt_exit(void) -{ -} -#endif - -static const dtrace_pattr_t sdt_attr = { +dtrace_mprovider_t sdt_providers[] = { + { "vtrace", "__vtrace_", &vtrace_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, + { "sysinfo", "__cpu_sysinfo_", &info_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, + { "vminfo", "__cpu_vminfo_", &info_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, + { "fpuinfo", "__fpuinfo_", &fpu_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, + { "sched", "__sched_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, + { "proc", "__proc_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, + { "io", "__io_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, + { "ip", "__ip_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, + { "tcp", "__tcp_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, + { "udp", "__udp_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, + { "mib", "__mib_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, + { "fsinfo", "__fsinfo_", &fsinfo_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, + { "iscsi", "__iscsi_", &iscsi_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, + { "nfsv3", "__nfsv3_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, + { "nfsv4", "__nfsv4_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, + { "xpv", "__xpv_", &xpv_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, + { "fc", "__fc_", &fc_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, + { "srp", "__srp_", &fc_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, + { "sysevent", "__sysevent_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, + { "sdt", NULL, &sdt_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, + { NULL } }; -extern int sdt_dev_init(void); -extern void sdt_dev_exit(void); - -DT_PROVIDER_MODULE(sdt, DTRACE_PRIV_KERNEL) - -MODULE_AUTHOR("Kris Van Hees (kris.van.hees@oracle.com)"); -MODULE_DESCRIPTION("Statically Defined Tracing"); -MODULE_VERSION("v0.1"); -MODULE_LICENSE("CDDL"); +DT_META_PROVIDER_MODULE(sdt) -- 2.50.1