Commit ab7476cf76e560f0efda2a631a70aabe93009025

Authored by Arjan van de Ven
Committed by Ingo Molnar
1 parent fb822db465

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  
... ... @@ -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 +}
... ... @@ -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;
... ... @@ -513,7 +513,7 @@
513 513 return buf;
514 514 }
515 515  
516   -static inline void *dereference_function_descriptor(void *ptr)
  516 +void *dereference_function_descriptor(void *ptr)
517 517 {
518 518 #if defined(CONFIG_IA64) || defined(CONFIG_PPC64)
519 519 void *p;