Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

alpha: exception table sorting

Exception fixups for sections other than .text (like one in futex_init())
break the natural ordering of fixup entries, so sorting is required.

Without that the result of the exception table search depends on phase of
the moon.

Signed-off-by: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Cc: Richard Henderson <rth@twiddle.net
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Ivan Kokshaysky and committed by
Linus Torvalds
08a42e86 1ffb1c0c

+41 -1
+2
arch/alpha/include/asm/uaccess.h
··· 507 507 (pc) + (_fixup)->fixup.bits.nextinsn; \ 508 508 }) 509 509 510 + #define ARCH_HAS_SORT_EXTABLE 511 + #define ARCH_HAS_SEARCH_EXTABLE 510 512 511 513 #endif /* __ALPHA_UACCESS_H */
+39 -1
arch/alpha/mm/extable.c
··· 3 3 */ 4 4 5 5 #include <linux/module.h> 6 + #include <linux/sort.h> 6 7 #include <asm/uaccess.h> 8 + 9 + static inline unsigned long ex_to_addr(const struct exception_table_entry *x) 10 + { 11 + return (unsigned long)&x->insn + x->insn; 12 + } 13 + 14 + static void swap_ex(void *a, void *b, int size) 15 + { 16 + struct exception_table_entry *ex_a = a, *ex_b = b; 17 + unsigned long addr_a = ex_to_addr(ex_a), addr_b = ex_to_addr(ex_b); 18 + unsigned int t = ex_a->fixup.unit; 19 + 20 + ex_a->fixup.unit = ex_b->fixup.unit; 21 + ex_b->fixup.unit = t; 22 + ex_a->insn = (int)(addr_b - (unsigned long)&ex_a->insn); 23 + ex_b->insn = (int)(addr_a - (unsigned long)&ex_b->insn); 24 + } 25 + 26 + /* 27 + * The exception table needs to be sorted so that the binary 28 + * search that we use to find entries in it works properly. 29 + * This is used both for the kernel exception table and for 30 + * the exception tables of modules that get loaded. 31 + */ 32 + static int cmp_ex(const void *a, const void *b) 33 + { 34 + const struct exception_table_entry *x = a, *y = b; 35 + 36 + /* avoid overflow */ 37 + if (ex_to_addr(x) > ex_to_addr(y)) 38 + return 1; 39 + if (ex_to_addr(x) < ex_to_addr(y)) 40 + return -1; 41 + return 0; 42 + } 7 43 8 44 void sort_extable(struct exception_table_entry *start, 9 45 struct exception_table_entry *finish) 10 46 { 47 + sort(start, finish - start, sizeof(struct exception_table_entry), 48 + cmp_ex, swap_ex); 11 49 } 12 50 13 51 const struct exception_table_entry * ··· 58 20 unsigned long mid_value; 59 21 60 22 mid = (last - first) / 2 + first; 61 - mid_value = (unsigned long)&mid->insn + mid->insn; 23 + mid_value = ex_to_addr(mid); 62 24 if (mid_value == value) 63 25 return mid; 64 26 else if (mid_value < value)