From 8327218a6c7495cf2387ba970aa8bac7e8a500de Mon Sep 17 00:00:00 2001 From: Kris Van Hees Date: Mon, 12 Jun 2017 09:29:16 -0400 Subject: [PATCH] dtrace: convert FBT blacklist to RB-tree The blacklist for FBT was implemented as a sorted list, populated from a static list of functions. In order to allow functions to be added from other places (i.e. programmatically), it has been converted to an RB-tree with an API to add functions and to traverse the list. It is still possible to add functions by address or to add them by symbol name, to be resolved into the corresponding address. Orabug: 26190412 Signed-off-by: Tomas Jedlicka Signed-off-by: Kris Van Hees Acked-by: Nick Alcock --- arch/sparc/kernel/dtrace_fbt.c | 49 +++++--------- arch/x86/kernel/dtrace_fbt.c | 57 ++++++---------- arch/x86/kernel/fbt_blacklist.h | 51 +++++++++++++- include/linux/dtrace_fbt.h | 13 +++- kernel/dtrace/Makefile | 2 +- kernel/dtrace/dtrace_fbt_core.c | 113 ++++++++++++++++++++++++++++++++ 6 files changed, 209 insertions(+), 76 deletions(-) create mode 100644 kernel/dtrace/dtrace_fbt_core.c diff --git a/arch/sparc/kernel/dtrace_fbt.c b/arch/sparc/kernel/dtrace_fbt.c index 2178e7736f7f..e1c07b24b189 100644 --- a/arch/sparc/kernel/dtrace_fbt.c +++ b/arch/sparc/kernel/dtrace_fbt.c @@ -130,28 +130,15 @@ #undef BL_DENTRY #undef BL_SENTRY -typedef struct _bl_entry { - void *addr; - const char *name; -} bl_entry; - -static bl_entry blacklist[] = { -#define BL_SENTRY(tp, nm) { (void *)&nm, __stringify(nm) }, -#define BL_DENTRY(tp, nm) { NULL, __stringify(nm) }, +static void +dtrace_fbt_populate_bl(void) +{ +#define BL_SENTRY(tp, nm) dtrace_fbt_bl_add((unsigned long)&nm, __stringify(nm)); +#define BL_DENTRY(tp, nm) dtrace_fbt_bl_add(0, __stringify(nm)); #include "fbt_blacklist.h" #undef BL_DENTRY #undef BL_SENTRY }; -static int blacklist_len = ARRAY_SIZE(blacklist); - -static int bl_entry_cmp(const void *xx, const void *yy) -{ - bl_entry *x = (bl_entry *)xx; - bl_entry *y = (bl_entry *)yy; - - return x->addr > y->addr ? 1 - : x->addr < y->addr ? -1 : 0; -} void dtrace_fbt_init(fbt_add_probe_fn fbt_add_probe) { @@ -159,18 +146,14 @@ void dtrace_fbt_init(fbt_add_probe_fn fbt_add_probe) struct kallsym_iter sym; size_t blpos = 0; asm_instr_t *paddr = NULL; + dt_fbt_bl_entry_t *blent = NULL; /* * Look up any unresolved symbols in the blacklist, and sort the list * by ascending address. */ - for (pos = 0; pos < blacklist_len; pos++) { - bl_entry *be = &blacklist[pos]; - - if (!be->addr) - be->addr = (void *)kallsyms_lookup_name(be->name); - } - sort(blacklist, blacklist_len, sizeof(bl_entry), bl_entry_cmp, NULL); + dtrace_fbt_populate_bl(); + blent = dtrace_fbt_bl_first(); pos = 0; kallsyms_iter_reset(&sym, 0); @@ -201,15 +184,15 @@ void dtrace_fbt_init(fbt_add_probe_fn fbt_add_probe) continue; /* - * See if the symbol is on the blacklist. Since both lists are - * sorted by ascending address we can use concurrent traversal - * of both lists. + * See if the symbol is on the FBT's blacklist. Since both + * iterators are workng in sort order by ascending address we + * can use concurrent traversal. */ - while (blpos < blacklist_len && - blacklist[blpos].addr < (void *)sym.value) - blpos++; - - if (blacklist[blpos].addr == (void *)sym.value) + while (blent != NULL && + dtrace_fbt_bl_entry_addr(blent) < sym.value) { + blent = dtrace_fbt_bl_next(blent); + } + if (dtrace_fbt_bl_entry_addr(blent) == sym.value) continue; /* diff --git a/arch/x86/kernel/dtrace_fbt.c b/arch/x86/kernel/dtrace_fbt.c index 97ee749665c8..6786a7dbcac0 100644 --- a/arch/x86/kernel/dtrace_fbt.c +++ b/arch/x86/kernel/dtrace_fbt.c @@ -29,51 +29,29 @@ #undef BL_DENTRY #undef BL_SENTRY -typedef struct _bl_entry { - void *addr; - const char *name; -} bl_entry; - -static bl_entry blacklist[] = { -#define BL_SENTRY(tp, nm) { (void *)&nm, __stringify(nm) }, -#define BL_DENTRY(tp, nm) { NULL, __stringify(nm) }, +static void +dtrace_fbt_populate_bl(void) +{ +#define BL_SENTRY(tp, nm) dtrace_fbt_bl_add((unsigned long)&nm, __stringify(nm)); +#define BL_DENTRY(tp, nm) dtrace_fbt_bl_add(0, __stringify(nm)); #include "fbt_blacklist.h" -#undef BL_DENTRY #undef BL_SENTRY -}; -static int blacklist_len = ARRAY_SIZE(blacklist); - -static int bl_entry_cmp(const void *xx, const void *yy) -{ - bl_entry *x = (bl_entry *)xx; - bl_entry *y = (bl_entry *)yy; - - if (x->addr > y->addr) - return 1; - else if (x->addr < y->addr) - return -1; - else - return 0; +#undef BL_DENTRY } void dtrace_fbt_init(fbt_add_probe_fn fbt_add_probe) { loff_t pos; struct kallsym_iter sym; - size_t blpos = 0; asm_instr_t *paddr = NULL; + dt_fbt_bl_entry_t *blent = NULL; /* * Look up any unresolved symbols in the blacklist, and sort the list * by ascending address. */ - for (pos = 0; pos < blacklist_len; pos++) { - bl_entry *be = &blacklist[pos]; - - if (!be->addr) - be->addr = (void *)kallsyms_lookup_name(be->name); - } - sort(blacklist, blacklist_len, sizeof(bl_entry), bl_entry_cmp, NULL); + dtrace_fbt_populate_bl(); + blent = dtrace_fbt_bl_first(); pos = 0; kallsyms_iter_reset(&sym, 0); @@ -99,15 +77,18 @@ void dtrace_fbt_init(fbt_add_probe_fn fbt_add_probe) if (!core_kernel_text(sym.value)) continue; + /* TODO: Jumplabel blacklist ? */ + /* - * See if the symbol is on the blacklist. Since both lists are - * sorted by ascending address we can use concurrent traversal - * of both lists. + * See if the symbol is on the FBT's blacklist. Since both + * iterators are workng in sort order by ascending address we + * can use concurrent traversal. */ - while (blpos < blacklist_len && - blacklist[blpos].addr < (void *)sym.value) - blpos++; - if (blacklist[blpos].addr == (void *)sym.value) + while (blent != NULL && + dtrace_fbt_bl_entry_addr(blent) < sym.value) { + blent = dtrace_fbt_bl_next(blent); + } + if (dtrace_fbt_bl_entry_addr(blent) == sym.value) continue; /* diff --git a/arch/x86/kernel/fbt_blacklist.h b/arch/x86/kernel/fbt_blacklist.h index 3294cd428a45..41b7244199cb 100644 --- a/arch/x86/kernel/fbt_blacklist.h +++ b/arch/x86/kernel/fbt_blacklist.h @@ -1,16 +1,61 @@ +/* + * Functions used in die notifier chain calling. + */ +BL_SENTRY(void *, notify_die) BL_DENTRY(void *, notifier_call_chain) BL_SENTRY(typeof(__atomic_notifier_call_chain), __atomic_notifier_call_chain) BL_SENTRY(typeof(atomic_notifier_call_chain), atomic_notifier_call_chain) BL_SENTRY(typeof(__raw_notifier_call_chain), __raw_notifier_call_chain) BL_SENTRY(typeof(raw_notifier_call_chain), raw_notifier_call_chain) -BL_SENTRY(typeof(idr_find_slowpath), idr_find_slowpath) BL_DENTRY(void *, hw_breakpoint_exceptions_notify) BL_DENTRY(void *, kprobe_exceptions_notify) -BL_SENTRY(void *, notify_die) -BL_DENTRY(void *, pvclock_clocksource_read) + +BL_SENTRY(typeof(idr_find_slowpath), idr_find_slowpath) + +/* + * Functions used to update vtime in probe context. + */ BL_SENTRY(typeof(ktime_get_raw_fast_ns), ktime_get_raw_fast_ns) +/* xen_clocksource */ +BL_DENTRY(void *, xen_clocksource_get_cycles) +BL_DENTRY(void *, xen_clocksource_read) +BL_DENTRY(void *, pvclock_clocksource_read) +BL_DENTRY(void *, pvclock_touch_watchdogs) +BL_DENTRY(void *, touch_softlockup_watchdog_sync) +BL_DENTRY(void *, clocksource_touch_watchdog) +BL_DENTRY(void *, clocksource_resume_watchdog) +BL_DENTRY(void *, reset_hung_task_detector) +/* clocksource_tsc */ +BL_DENTRY(void *, read_tsc) +BL_DENTRY(void *, get_cycles) +/* clocksource_hpet */ +BL_DENTRY(void *, read_hpet) +BL_DENTRY(void *, hpet_readl) +/* kvm_clock */ +BL_DENTRY(void *, kvm_clock_get_cycles) +BL_DENTRY(void *, kvm_clock_read) + +/* + * Functions used in trap handling. + */ BL_DENTRY(void *, fixup_exception) +BL_DENTRY(void *, paranoid_entry) +BL_DENTRY(void *, kgdb_ll_trap) +BL_DENTRY(void *, error_entry) +BL_DENTRY(void *, xen_int3) +BL_DENTRY(void *, ftrace_int3_handler) +BL_SENTRY(typeof(poke_int3_handler), poke_int3_handler) +BL_DENTRY(void *, fixup_bad_iret) +BL_DENTRY(void *, xen_adjust_exception_frame) +BL_DENTRY(void *, paravirt_nop) +BL_DENTRY(void *, ist_enter) +BL_DENTRY(void *, rcu_nmi_enter) +BL_DENTRY(void *, rcu_nmi_exit) +BL_DENTRY(void *, ist_exit) +/* + * Functions used in page fault handling. + */ BL_SENTRY(void *, do_page_fault) BL_DENTRY(void *, __do_page_fault) BL_DENTRY(void *, down_read_trylock) diff --git a/include/linux/dtrace_fbt.h b/include/linux/dtrace_fbt.h index a7789eb84ec0..75c1e8745f2c 100644 --- a/include/linux/dtrace_fbt.h +++ b/include/linux/dtrace_fbt.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 Oracle, Inc. */ +/* Copyright (C) 2015, 2017, Oracle and/or its affiliates. All rights reserved. */ #ifndef _LINUX_DTRACE_FBT_H #define _LINUX_DTRACE_FBT_H @@ -29,4 +29,15 @@ typedef void *(*fbt_add_probe_fn)(struct module *, char *, int, int, asm_instr_t *, uintptr_t, void *); extern void dtrace_fbt_init(fbt_add_probe_fn); +/* + * Dynamic blacklist routines. + */ +typedef struct dt_fbt_bl_entry dt_fbt_bl_entry_t; + +extern dt_fbt_bl_entry_t *dtrace_fbt_bl_add(unsigned long, const char *); +extern dt_fbt_bl_entry_t *dtrace_fbt_bl_first(void); +extern dt_fbt_bl_entry_t *dtrace_fbt_bl_next(dt_fbt_bl_entry_t *); +extern unsigned long dtrace_fbt_bl_entry_addr(dt_fbt_bl_entry_t *); +extern const char *dtrace_fbt_bl_entry_name(dt_fbt_bl_entry_t *); + #endif /* _LINUX_DTRACE_FBT_H */ diff --git a/kernel/dtrace/Makefile b/kernel/dtrace/Makefile index e0d84ccf91ef..066bbace9572 100644 --- a/kernel/dtrace/Makefile +++ b/kernel/dtrace/Makefile @@ -10,6 +10,6 @@ DT_CORE_ARCH_OBJS = $(addprefix ../../arch/$(SRCARCH)/kernel/, \ ifdef CONFIG_DT_CORE obj-y += cyclic.o dtrace_os.o dtrace_cpu.o \ - dtrace_sdt_core.o \ + dtrace_sdt_core.o dtrace_fbt_core.o \ $(DT_CORE_ARCH_OBJS) endif diff --git a/kernel/dtrace/dtrace_fbt_core.c b/kernel/dtrace/dtrace_fbt_core.c new file mode 100644 index 000000000000..3b2ca4432dc5 --- /dev/null +++ b/kernel/dtrace/dtrace_fbt_core.c @@ -0,0 +1,113 @@ +/* + * FILE: dtrace_fbt_core.c + * DESCRIPTION: Dynamic Tracing: FBT common code + * + * Copyright (C) 2017, Oracle and/or its affiliates. All rights reserved. + */ + +#include +#include +#include +#include +#include + +struct dt_fbt_bl_entry { + struct rb_node dfbe_node; + unsigned long dfbe_addr; + const char *dfbe_name; +}; + +static struct rb_root dt_fbt_root = RB_ROOT; + +dt_fbt_bl_entry_t * +dtrace_fbt_bl_add(unsigned long addr, const char *name) +{ + struct rb_node **p = &dt_fbt_root.rb_node; + struct rb_node *parent = NULL; + struct dt_fbt_bl_entry *entry; + + /* + * If no address was given, we need to do a symbol name lookup: + * - If no symbol name was given, we cannot add anything. + * - If the lookup failed, we cannot add anything. + */ + if (addr == 0) { + if (name == NULL) + return NULL; + + addr = kallsyms_lookup_name(name); + + if (addr == 0) + return NULL; + } + + /* Find place in the tree. */ + while (*p) { + parent = *p; + entry = rb_entry(parent, dt_fbt_bl_entry_t, dfbe_node); + + if (addr > entry->dfbe_addr) + p = &parent->rb_right; + else if (addr < entry->dfbe_addr) + p = &parent->rb_left; + else + return NULL; /* no duplicates please */ + } + + /* Create a new blacklist entry. */ + if ((entry = kmalloc(sizeof(*entry), GFP_KERNEL)) == NULL) + return NULL; + + entry->dfbe_name = name; + entry->dfbe_addr = addr; + + /* Update the tree. */ + rb_link_node(&entry->dfbe_node, parent, p); + rb_insert_color(&entry->dfbe_node, &dt_fbt_root); + + return entry; +} + +/* + * Iterators for blacklisted symbols. The iteration happens in sort order by + * virtual memory address. Symbols with pending resolution are inored. + */ +dt_fbt_bl_entry_t * +dtrace_fbt_bl_first(void) +{ + struct rb_node *node = rb_first(&dt_fbt_root); + + if (node == NULL) + return (NULL); + + return (rb_entry(node, dt_fbt_bl_entry_t, dfbe_node)); +} + +dt_fbt_bl_entry_t * +dtrace_fbt_bl_next(dt_fbt_bl_entry_t *entry) +{ + struct rb_node *node = rb_next(&entry->dfbe_node); + + if (node == NULL) + return (NULL); + + return (rb_entry(node, dt_fbt_bl_entry_t, dfbe_node)); +} + +unsigned long +dtrace_fbt_bl_entry_addr(dt_fbt_bl_entry_t *entry) +{ + if (entry == NULL) + return (0); + + return (entry->dfbe_addr); +} + +const char * +dtrace_fbt_bl_entry_name(dt_fbt_bl_entry_t *entry) +{ + if (entry == NULL) + return (NULL); + + return (entry->dfbe_name); +} -- 2.50.1