From: Kris Van Hees Date: Mon, 12 Jun 2017 13:29:16 +0000 (-0400) Subject: dtrace: convert FBT blacklist to RB-tree X-Git-Tag: v4.1.12-105.0.20170705_2000~12^2~1 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=8327218a6c7495cf2387ba970aa8bac7e8a500de;p=users%2Fjedix%2Flinux-maple.git 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 --- diff --git a/arch/sparc/kernel/dtrace_fbt.c b/arch/sparc/kernel/dtrace_fbt.c index 2178e7736f7f3..e1c07b24b1893 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 97ee749665c8a..6786a7dbcac0d 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 3294cd428a45c..41b7244199cb8 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 a7789eb84ec09..75c1e8745f2c6 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 e0d84ccf91ef8..066bbace95723 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 0000000000000..3b2ca4432dc5c --- /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); +}