#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)
{
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);
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;
/*
#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);
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;
/*
+/*
+ * 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)
-/* 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
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 */
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
--- /dev/null
+/*
+ * FILE: dtrace_fbt_core.c
+ * DESCRIPTION: Dynamic Tracing: FBT common code
+ *
+ * Copyright (C) 2017, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <linux/kernel.h>
+#include <linux/kallsyms.h>
+#include <linux/rbtree.h>
+#include <linux/slab.h>
+#include <linux/dtrace_fbt.h>
+
+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);
+}