From: Kris Van Hees Date: Thu, 19 Apr 2012 21:19:40 +0000 (-0400) Subject: dtrace: add sched-tick SDT probe and FBT probe point discovery/creation X-Git-Tag: v4.1.12-92~313^2~151 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=2a597d2b0c8b79bef74c24a5ebf631be76f8862c;p=users%2Fjedix%2Flinux-maple.git dtrace: add sched-tick SDT probe and FBT probe point discovery/creation 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 --- diff --git a/include/linux/dtrace_os.h b/include/linux/dtrace_os.h index 87797613e360..fe7a17ad728d 100644 --- a/include/linux/dtrace_os.h +++ b/include/linux/dtrace_os.h @@ -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_ */ diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h index 6883e197acb9..4dcdda928f09 100644 --- a/include/linux/kallsyms.h +++ b/include/linux/kallsyms.h @@ -7,6 +7,7 @@ #include #include +#include #include #define KSYM_NAME_LEN 128 @@ -16,6 +17,17 @@ 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) diff --git a/include/linux/module.h b/include/linux/module.h index 6eb2674fb8f7..dc5f02be0980 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -21,6 +21,9 @@ #include #include +#include +#include + /* 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 */ diff --git a/include/linux/sdt.h b/include/linux/sdt.h index 8a58a51cb13e..62db6436dfb2 100644 --- a/include/linux/sdt.h +++ b/include/linux/sdt.h @@ -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: */ diff --git a/kernel/dtrace/dtrace_os.c b/kernel/dtrace/dtrace_os.c index cc0d8e20a993..4c2c1cbb2c03 100644 --- a/kernel/dtrace/dtrace_os.c +++ b/kernel/dtrace/dtrace_os.c @@ -15,10 +15,49 @@ #include #include #include +#include #include #include #include +/* + * 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); diff --git a/kernel/dtrace/sdt_register.c b/kernel/dtrace/sdt_register.c index dd457de7917f..25e9dda2cff1 100644 --- a/kernel/dtrace/sdt_register.c +++ b/kernel/dtrace/sdt_register.c @@ -2,11 +2,10 @@ /* register static dtrace probe points */ -#define DEBUG 1 - #include #include #include +#include #include #include #include @@ -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; diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index 5c5987f10819..7b92a0f0c43d 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -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. */ diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 2ece3aa5069c..fe2174eb87e3 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -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();