Commit ab7476cf76e560f0efda2a631a70aabe93009025
Committed by
Ingo Molnar
1 parent
fb822db465
Exists in
master
and in
20 other branches
debug: add notifier chain debugging, v2
- 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>
Showing 4 changed files with 21 additions and 10 deletions Side-by-side Diff
include/linux/kernel.h
... | ... | @@ -187,6 +187,9 @@ |
187 | 187 | extern int core_kernel_text(unsigned long addr); |
188 | 188 | extern int __kernel_text_address(unsigned long addr); |
189 | 189 | extern int kernel_text_address(unsigned long addr); |
190 | +extern int func_ptr_is_kernel_text(void *ptr); | |
191 | +extern void *dereference_function_descriptor(void *ptr); | |
192 | + | |
190 | 193 | struct pid; |
191 | 194 | extern struct pid *session_of_pgrp(struct pid *pgrp); |
192 | 195 |
kernel/extable.c
... | ... | @@ -66,4 +66,20 @@ |
66 | 66 | return 1; |
67 | 67 | return module_text_address(addr) != NULL; |
68 | 68 | } |
69 | + | |
70 | +/* | |
71 | + * On some architectures (PPC64, IA64) function pointers | |
72 | + * are actually only tokens to some data that then holds the | |
73 | + * real function address. As a result, to find if a function | |
74 | + * pointer is part of the kernel text, we need to do some | |
75 | + * special dereferencing first. | |
76 | + */ | |
77 | +int func_ptr_is_kernel_text(void *ptr) | |
78 | +{ | |
79 | + unsigned long addr; | |
80 | + addr = (unsigned long) dereference_function_descriptor(ptr); | |
81 | + if (core_kernel_text(addr)) | |
82 | + return 1; | |
83 | + return module_text_address(addr) != NULL; | |
84 | +} |
kernel/notifier.c
... | ... | @@ -21,10 +21,6 @@ |
21 | 21 | static int notifier_chain_register(struct notifier_block **nl, |
22 | 22 | struct notifier_block *n) |
23 | 23 | { |
24 | - if (!kernel_text_address((unsigned long)n->notifier_call)) { | |
25 | - WARN(1, "Invalid notifier registered!"); | |
26 | - return 0; | |
27 | - } | |
28 | 24 | while ((*nl) != NULL) { |
29 | 25 | if (n->priority > (*nl)->priority) |
30 | 26 | break; |
... | ... | @@ -38,10 +34,6 @@ |
38 | 34 | static int notifier_chain_cond_register(struct notifier_block **nl, |
39 | 35 | struct notifier_block *n) |
40 | 36 | { |
41 | - if (!kernel_text_address((unsigned long)n->notifier_call)) { | |
42 | - WARN(1, "Invalid notifier registered!"); | |
43 | - return 0; | |
44 | - } | |
45 | 37 | while ((*nl) != NULL) { |
46 | 38 | if ((*nl) == n) |
47 | 39 | return 0; |
... | ... | @@ -92,7 +84,7 @@ |
92 | 84 | next_nb = rcu_dereference(nb->next); |
93 | 85 | |
94 | 86 | #ifdef CONFIG_DEBUG_NOTIFIERS |
95 | - if (!kernel_text_address((unsigned long)nb->notifier_call)) { | |
87 | + if (unlikely(!func_ptr_is_kernel_text(nb->notifier_call))) { | |
96 | 88 | WARN(1, "Invalid notifier called!"); |
97 | 89 | nb = next_nb; |
98 | 90 | continue; |
lib/vsprintf.c