]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
dtrace: add sched-tick SDT probe and FBT probe point discovery/creation
authorKris Van Hees <kris.van.hees@oracle.com>
Thu, 19 Apr 2012 21:19:40 +0000 (17:19 -0400)
committerNick Alcock <nick.alcock@oracle.com>
Mon, 29 Jun 2015 21:40:24 +0000 (22:40 +0100)
Move code around for the kernel pseudo-module handling since it gets used
by both the SDT code and the FBT code.

Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com>
include/linux/dtrace_os.h
include/linux/kallsyms.h
include/linux/module.h
include/linux/sdt.h
kernel/dtrace/dtrace_os.c
kernel/dtrace/sdt_register.c
kernel/kallsyms.c
kernel/time/timer.c

index 87797613e360090bc55d3c78f7ffae0c068215e9..fe7a17ad728dd51324030756a29e4e33e55d3ac4 100644 (file)
@@ -18,6 +18,11 @@ typedef uint32_t dtrace_id_t;
 #define SCE_RT_SIGRETURN       6
 #define SCE_nr_stubs           7
 
+extern struct module   *dtrace_kmod;
+
+extern void dtrace_os_init(void);
+extern void dtrace_os_exit(void);
+
 extern void dtrace_enable(void);
 extern void dtrace_disable(void);
 
@@ -64,4 +69,13 @@ typedef struct stacktrace_state {
 
 extern void dtrace_stacktrace(stacktrace_state_t *);
 
+#define FBT_PUSHL_EBP  0x55
+#define FBT_RET                0xc3
+#define FBT_RET_IMM16  0xc2
+
+typedef void           *(fbt_provide_fn)(struct module *, char *, uint8_t,
+                                         uint8_t *, void *);
+
+extern void dtrace_fbt_init(fbt_provide_fn);
+
 #endif /* _DTRACE_OS_H_ */
index 6883e197acb9e939156c4934d9cc7150b1b107f5..4dcdda928f094a5f982378f675b52d8d9c592b3c 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/errno.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/stddef.h>
 
 #define KSYM_NAME_LEN 128
 struct module;
 
 #ifdef CONFIG_KALLSYMS
+/* To avoid using get_symbol_offset for every symbol, we carry prefix along. */
+struct kallsym_iter {
+       loff_t pos;
+       unsigned long value;
+       unsigned int nameoff; /* If iterating in core kernel symbols. */
+       char type;
+       char name[KSYM_NAME_LEN];
+       char module_name[MODULE_NAME_LEN];
+       int exported;
+};
+
 /* Lookup the address for a symbol. Returns 0 if not found. */
 unsigned long kallsyms_lookup_name(const char *name);
 
@@ -45,6 +57,8 @@ extern void __print_symbol(const char *fmt, unsigned long address);
 int lookup_symbol_name(unsigned long addr, char *symname);
 int lookup_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name);
 
+extern void kallsyms_iter_reset(struct kallsym_iter *, loff_t);
+extern int kallsyms_iter_update(struct kallsym_iter *, loff_t);
 #else /* !CONFIG_KALLSYMS */
 
 static inline unsigned long kallsyms_lookup_name(const char *name)
index 6eb2674fb8f756cbdc7393b24b1e33489f0876c8..dc5f02be0980d482774bbe7379a02a9eaed7e6fb 100644 (file)
@@ -21,6 +21,9 @@
 #include <linux/percpu.h>
 #include <asm/module.h>
 
+#include <trace/events/module.h>
+#include <linux/sdt.h>
+
 /* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */
 #define MODULE_SIG_STRING "~Module signature appended~\n"
 
@@ -351,7 +354,9 @@ struct module {
 #endif
 
 #if defined(CONFIG_DTRACE) || defined(CONFIG_DTRACE_MODULE)
-       struct sdt_probedesc *sdt_probes;
+       size_t fbt_nprobes;
+
+       sdt_probedesc_t *sdt_probes;
        unsigned int num_dtrace_probes; /* from kernel build */
        size_t sdt_nprobes;             /* managed at probe load time */
        int mod_nenabled;       /* # of enabled dtrace probes in module */
index 8a58a51cb13efaec750c429721d8eb2426bdb893..62db6436dfb2554694f3ebed48a0f4f4a83a705c 100644 (file)
@@ -138,12 +138,6 @@ typedef struct dtrace_sdt_probeinfo {
 
 void dtrace_register_builtins(void);
 
-#ifdef DEBUG
-#define DPRINTK(fmt, args...) printk(KERN_INFO "%s: " fmt, __func__, ## args)
-#else
-#define DPRINTK(fmt, args...)
-#endif
-
 #endif /* __KERNEL__ */
 
 #else /* DTRACE not enabled: */
index cc0d8e20a993d886b4e79de1a33aa6fbb97e0de7..4c2c1cbb2c036975e871c85c680b7711b220f60f 100644 (file)
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/kallsyms.h>
 #include <asm/insn.h>
 #include <asm/stacktrace.h>
 #include <asm/syscalls.h>
 
+/*
+ * Perform OS specific DTrace setup.
+ */
+struct module  *dtrace_kmod = NULL;
+EXPORT_SYMBOL(dtrace_kmod);
+
+void dtrace_os_init(void)
+{
+       if (dtrace_kmod != NULL) {
+               pr_warning("%s: cannot be called twice\n", __func__);
+               return;
+       }
+
+       dtrace_kmod = kzalloc(sizeof(struct module), GFP_KERNEL);
+       if (dtrace_kmod == NULL) {
+               pr_warning("%s: cannot allocate kernel pseudo-module\n",
+                          __func__);
+               return;
+       }
+
+       dtrace_kmod->state = MODULE_STATE_LIVE;
+       strlcpy(dtrace_kmod->name, "vmlinux", MODULE_NAME_LEN);
+}
+EXPORT_SYMBOL(dtrace_os_init);
+
+void dtrace_os_exit(void)
+{
+       if (dtrace_kmod == NULL) {
+               pr_warning("%s: kernel pseudo-module not allocated\n",
+                          __func__);
+               return;
+       }
+
+       kfree(dtrace_kmod);
+       dtrace_kmod = NULL;
+}
+EXPORT_SYMBOL(dtrace_os_exit);
+
 /*
  * Return a high resolution timer value that is guaranteed to always increase.
  */
@@ -381,7 +420,7 @@ void dtrace_invop_remove(int (*func)(struct pt_regs *))
 EXPORT_SYMBOL(dtrace_invop_remove);
 
 /*---------------------------------------------------------------------------*\
-(* SYSTEM CALL PROBING SUPPORT                                               *)
+(* SYSTEM CALL TRACING SUPPORT                                               *)
 \*---------------------------------------------------------------------------*/
 void (*systrace_probe)(dtrace_id_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t,
                       uintptr_t, uintptr_t);
@@ -696,3 +735,62 @@ long dtrace_rt_sigreturn(struct pt_regs *regs)
 
        return rc;
 }
+
+/*---------------------------------------------------------------------------*\
+(* FUNCTION BOUNDARY TRACING (FBT) SUPPORT                                   *)
+\*---------------------------------------------------------------------------*/
+
+void dtrace_fbt_init(fbt_provide_fn *pfn)
+{
+       loff_t                  pos = 0;
+       struct kallsym_iter     iter, sym;
+
+       kallsyms_iter_update(&iter, 0);
+       if (!kallsyms_iter_update(&iter, pos++))
+               return;
+
+       while (pos > 0) {
+               sym = iter;
+               if (!kallsyms_iter_update(&iter, pos++))
+                       pos = 0;
+
+               if (sym.module_name[0] != '\0')
+                       break;
+
+               if (sym.type == 'T' || sym.type == 't' || sym.type == 'W') {
+                       uint8_t *addr, *end;
+
+                       addr = (uint8_t *)sym.value;
+                       end = (uint8_t *)iter.value;
+
+                       if (*addr == FBT_PUSHL_EBP) {
+                               struct insn     insn;
+                               void            *pfbt = NULL;
+
+                               (*pfn)(dtrace_kmod, sym.name, FBT_PUSHL_EBP,
+                                      addr, NULL);
+
+                               while (addr < end) {
+                                       uint8_t opc;
+
+                                       insn_init(&insn, addr, 1);
+                                       insn_get_opcode(&insn);
+
+                                       opc = insn.opcode.bytes[0];
+
+                                       if (opc == FBT_RET ||
+                                           opc == FBT_RET_IMM16) {
+                                               pfbt = (*pfn)(dtrace_kmod,
+                                                             sym.name, opc,
+                                                             addr, pfbt);
+                                       }
+
+                                       insn_get_length(&insn);
+
+                                       addr += insn.length;
+                               }
+                       }
+               }
+       }
+}
+EXPORT_SYMBOL(dtrace_fbt_init);
index dd457de7917f606177c9afef5a60b7a23612b60f..25e9dda2cff1c9bdf16061beb1a3db00a229f0ed 100644 (file)
@@ -2,11 +2,10 @@
 
 /* register static dtrace probe points */
 
-#define DEBUG  1
-
 #include <linux/kernel.h>
 #include <linux/memory.h>
 #include <linux/module.h>
+#include <linux/dtrace_os.h>
 #include <linux/sdt.h>
 #include <linux/slab.h>
 #include <linux/string.h>
@@ -20,9 +19,6 @@
 
 const char             *sdt_prefix = "__dtrace_probe_";
 
-struct module          *dtrace_kmod;
-EXPORT_SYMBOL(dtrace_kmod);
-
 void sdt_probe_enable(sdt_instr_t *addr)
 {
        text_poke(addr, ((unsigned char []){SDT_TRAP_INSTR}), 1);
@@ -78,6 +74,15 @@ void dtrace_register_builtins(void)
        void                    *nextpi;
        uint8_t                 nops[SDT_NOP_SIZE];
 
+       if (dtrace_kmod == NULL) {
+               pr_warning("%s: no kernel pseudo-module allocated\n",
+                          __func__);
+               return;
+       }
+
+       if (dtrace_sdt_nprobes == 0)
+               return;
+
        /*
         * A little unusual, but potentially necessary.  While we could use a
         * single NOP sequence of length SDT_NOP_SIZE, we need to consider the
@@ -89,18 +94,6 @@ void dtrace_register_builtins(void)
        add_nops(nops, 1);
        add_nops(nops + 1, SDT_NOP_SIZE - 1);
 
-       dtrace_kmod = kzalloc(sizeof(struct module), GFP_KERNEL);
-       if (!dtrace_kmod) {
-               pr_warning("%s: cannot allocate kernel pseudo-module\n",
-                          __func__);
-               return;
-       }
-       dtrace_kmod->state = MODULE_STATE_LIVE;
-       strlcpy(dtrace_kmod->name, "vmlinux", MODULE_NAME_LEN);
-
-       if (dtrace_sdt_nprobes == 0)
-               return;
-
        for (cnt = 0; cnt < dtrace_sdt_nprobes; cnt++) {
                char    *func = pi->name + pi->name_len + 1;
 
index 5c5987f1081964109f96cd6cc52b285b948f0a9e..7b92a0f0c43de0da3335186a724c9ad6054b2ff8 100644 (file)
@@ -281,6 +281,7 @@ int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize,
 
        return !!module_address_lookup(addr, symbolsize, offset, NULL, namebuf);
 }
+EXPORT_SYMBOL_GPL(kallsyms_lookup_size_offset);
 
 /*
  * Lookup an address
@@ -444,17 +445,6 @@ void __print_symbol(const char *fmt, unsigned long address)
 }
 EXPORT_SYMBOL(__print_symbol);
 
-/* To avoid using get_symbol_offset for every symbol, we carry prefix along. */
-struct kallsym_iter {
-       loff_t pos;
-       unsigned long value;
-       unsigned int nameoff; /* If iterating in core kernel symbols. */
-       char type;
-       char name[KSYM_NAME_LEN];
-       char module_name[MODULE_NAME_LEN];
-       int exported;
-};
-
 static int get_ksymbol_mod(struct kallsym_iter *iter)
 {
        if (module_get_kallsym(iter->pos - kallsyms_num_syms, &iter->value,
@@ -479,15 +469,16 @@ static unsigned long get_ksymbol_core(struct kallsym_iter *iter)
        return off - iter->nameoff;
 }
 
-static void reset_iter(struct kallsym_iter *iter, loff_t new_pos)
+void kallsyms_iter_reset(struct kallsym_iter *iter, loff_t new_pos)
 {
        iter->name[0] = '\0';
        iter->nameoff = get_symbol_offset(new_pos);
        iter->pos = new_pos;
 }
+EXPORT_SYMBOL_GPL(kallsyms_iter_reset);
 
 /* Returns false if pos at or past end of file. */
-static int update_iter(struct kallsym_iter *iter, loff_t pos)
+int kallsyms_iter_update(struct kallsym_iter *iter, loff_t pos)
 {
        /* Module symbols can be accessed randomly. */
        if (pos >= kallsyms_num_syms) {
@@ -497,26 +488,27 @@ static int update_iter(struct kallsym_iter *iter, loff_t pos)
 
        /* If we're not on the desired position, reset to new position. */
        if (pos != iter->pos)
-               reset_iter(iter, pos);
+               kallsyms_iter_reset(iter, pos);
 
        iter->nameoff += get_ksymbol_core(iter);
        iter->pos++;
 
        return 1;
 }
+EXPORT_SYMBOL_GPL(kallsyms_iter_update);
 
 static void *s_next(struct seq_file *m, void *p, loff_t *pos)
 {
        (*pos)++;
 
-       if (!update_iter(m->private, *pos))
+       if (!kallsyms_iter_update(m->private, *pos))
                return NULL;
        return p;
 }
 
 static void *s_start(struct seq_file *m, loff_t *pos)
 {
-       if (!update_iter(m->private, *pos))
+       if (!kallsyms_iter_update(m->private, *pos))
                return NULL;
        return m->private;
 }
@@ -568,7 +560,7 @@ static int kallsyms_open(struct inode *inode, struct file *file)
        iter = __seq_open_private(file, &kallsyms_op, sizeof(*iter));
        if (!iter)
                return -ENOMEM;
-       reset_iter(iter, 0);
+       kallsyms_iter_reset(iter, 0);
 
        return 0;
 }
@@ -580,10 +572,10 @@ const char *kdb_walk_kallsyms(loff_t *pos)
        if (*pos == 0) {
                memset(&kdb_walk_kallsyms_iter, 0,
                       sizeof(kdb_walk_kallsyms_iter));
-               reset_iter(&kdb_walk_kallsyms_iter, 0);
+               kallsyms_iter_reset(&kdb_walk_kallsyms_iter, 0);
        }
        while (1) {
-               if (!update_iter(&kdb_walk_kallsyms_iter, *pos))
+               if (!kallsyms_iter_update(&kdb_walk_kallsyms_iter, *pos))
                        return NULL;
                ++*pos;
                /* Some debugging symbols have no name.  Ignore them. */
index 2ece3aa5069cade64b8c4982e920a45bea5ba232..fe2174eb87e388897159a8d7d21e55190e0d69e7 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/sched/sysctl.h>
 #include <linux/slab.h>
 #include <linux/compat.h>
+#include <linux/sdt.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -1390,6 +1391,8 @@ void update_process_times(int user_tick)
 {
        struct task_struct *p = current;
 
+       DTRACE_SCHED1(tick, struct task_struct *, p);
+
        /* Note: this timer irq context must be accounted for as well. */
        account_process_tick(p, user_tick);
        run_local_timers();