]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
SDT implementation (core kernel support for providing a list of static probe
authorKris Van Hees <kris.van.hees@oracle.com>
Mon, 5 Dec 2011 20:01:27 +0000 (15:01 -0500)
committerNick Alcock <nick.alcock@oracle.com>
Wed, 7 Dec 2011 17:46:15 +0000 (17:46 +0000)
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 <kris.van.hees@oracle.com>
dtrace/Kbuild
dtrace/dtrace.h
dtrace/dtrace_probe.c
dtrace/dtrace_state.c
dtrace/sdt.h [deleted file]
dtrace/sdt_dev.c
dtrace/sdt_impl.h
dtrace/sdt_mod.c

index 6ad516f6866913974c641c3bf42f51e3f996a519..b717dc0b3b41212960a3ae97353f7af0ef4a0c06 100644 (file)
@@ -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
index 73e2f157d5892b1db131d064efca75299afb7b7b..76a6e8da68a0c436572726c31238439701fa224e 100644 (file)
@@ -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()
 
index 771b813c81e19dc1289b37c88ce85935aaaeff2b..0cd23e9d83c030ccd20449d16533ce8922597f45 100644 (file)
@@ -32,6 +32,7 @@
 #include <asm/cmpxchg.h>
 
 #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
index 379772da22ee12c5ac329a891dfd33eed2ac297c..35e186a4209b501325f53d2e1ddcec0a1f62b3d5 100644 (file)
@@ -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 (file)
index 6ad3c80..0000000
+++ /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_ */
index 6a297c2ef5789f63df341525c56f9801ee5ae589..504e380be1713da3d3d416318ad329e13406e04e 100644 (file)
 #include <linux/fs.h>
 #include <linux/miscdevice.h>
 #include <linux/sdt.h>
+#include <linux/slab.h>
 
+#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);
 }
index 823cdf180e59ecdba6ce299cf422c2470d8c9cb1..31a7788b13a9938a5a8670539691f9d6b90143e1 100644 (file)
@@ -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 <linux/sdt.h>
 
-#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_ */
index 3742b782c53087f72c02c5929760792d65ad888b..cbb93d30691f9ab849ece8ad9b1ab85ae26fca98 100644 (file)
@@ -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
  * Use is subject to license terms.
  */
 
-#include <linux/gfp.h>
-#include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/ptrace.h>
-#include <linux/sdt.h>
-#include <linux/slab.h>
 
 #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 = "<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);
-
-                       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)