]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
debug: add notifier chain debugging, v2
authorArjan van de Ven <arjan@linux.intel.com>
Fri, 15 Aug 2008 22:29:38 +0000 (15:29 -0700)
committerIngo Molnar <mingo@elte.hu>
Wed, 10 Sep 2008 07:08:53 +0000 (09:08 +0200)
- unbreak ia64 (and powerpc) where function pointers dont
  point at code but at data (reported by Tony Luck)

[ mingo@elte.hu: various cleanups ]

Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
include/linux/kernel.h
kernel/extable.c
kernel/notifier.c
lib/vsprintf.c

index 2651f805ba6d771b9ec1f26078609aebdb198853..4e1366b552ae9356bd234cc355105321a57d46b8 100644 (file)
@@ -187,6 +187,9 @@ extern unsigned long long memparse(char *ptr, char **retptr);
 extern int core_kernel_text(unsigned long addr);
 extern int __kernel_text_address(unsigned long addr);
 extern int kernel_text_address(unsigned long addr);
+extern int func_ptr_is_kernel_text(void *ptr);
+extern void *dereference_function_descriptor(void *ptr);
+
 struct pid;
 extern struct pid *session_of_pgrp(struct pid *pgrp);
 
index a26cb2e170237d849c9f87038a6def48ee948dd6..adf0cc9c02d6873d50c48edf4c34b44a32bf48b9 100644 (file)
@@ -66,3 +66,19 @@ int kernel_text_address(unsigned long addr)
                return 1;
        return module_text_address(addr) != NULL;
 }
+
+/*
+ * On some architectures (PPC64, IA64) function pointers
+ * are actually only tokens to some data that then holds the
+ * real function address. As a result, to find if a function
+ * pointer is part of the kernel text, we need to do some
+ * special dereferencing first.
+ */
+int func_ptr_is_kernel_text(void *ptr)
+{
+       unsigned long addr;
+       addr = (unsigned long) dereference_function_descriptor(ptr);
+       if (core_kernel_text(addr))
+               return 1;
+       return module_text_address(addr) != NULL;
+}
index 143fdd77dbf76f2afcb62d25c10bdb0fb5fc3314..0f39e398ef609cbf11ba04ce4977e14d2f8518fa 100644 (file)
@@ -21,10 +21,6 @@ BLOCKING_NOTIFIER_HEAD(reboot_notifier_list);
 static int notifier_chain_register(struct notifier_block **nl,
                struct notifier_block *n)
 {
-       if (!kernel_text_address((unsigned long)n->notifier_call)) {
-               WARN(1, "Invalid notifier registered!");
-               return 0;
-       }
        while ((*nl) != NULL) {
                if (n->priority > (*nl)->priority)
                        break;
@@ -38,10 +34,6 @@ static int notifier_chain_register(struct notifier_block **nl,
 static int notifier_chain_cond_register(struct notifier_block **nl,
                struct notifier_block *n)
 {
-       if (!kernel_text_address((unsigned long)n->notifier_call)) {
-               WARN(1, "Invalid notifier registered!");
-               return 0;
-       }
        while ((*nl) != NULL) {
                if ((*nl) == n)
                        return 0;
@@ -92,7 +84,7 @@ static int __kprobes notifier_call_chain(struct notifier_block **nl,
                next_nb = rcu_dereference(nb->next);
 
 #ifdef CONFIG_DEBUG_NOTIFIERS
-               if (!kernel_text_address((unsigned long)nb->notifier_call)) {
+               if (unlikely(!func_ptr_is_kernel_text(nb->notifier_call))) {
                        WARN(1, "Invalid notifier called!");
                        nb = next_nb;
                        continue;
index d8d1d1142248a511561b401a87b1590a5f94ba33..f5e5ffb9942fe9e4a3274b9729fb45c280ef119a 100644 (file)
@@ -513,7 +513,7 @@ static char *string(char *buf, char *end, char *s, int field_width, int precisio
        return buf;
 }
 
-static inline void *dereference_function_descriptor(void *ptr)
+void *dereference_function_descriptor(void *ptr)
 {
 #if defined(CONFIG_IA64) || defined(CONFIG_PPC64)
        void *p;