diff options
author | Thomas Meyer <thomas@m3y3r.de> | 2017-07-10 18:51:58 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-10 19:32:35 -0400 |
commit | a94c33dd1f677d16c4f1a162b4b3e9eba1b07c24 (patch) | |
tree | c5a55e93fc355f73d614b0608dac3652b8048adf | |
parent | 12e8fd6fd380261fd200d2e8f7a519ade73ea05b (diff) |
lib/extable.c: use bsearch() library function in search_extable()
[thomas@m3y3r.de: v3: fix arch specific implementations]
Link: http://lkml.kernel.org/r/1497890858.12931.7.camel@m3y3r.de
Signed-off-by: Thomas Meyer <thomas@m3y3r.de>
Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | arch/mips/kernel/module.c | 3 | ||||
-rw-r--r-- | arch/mips/kernel/traps.c | 3 | ||||
-rw-r--r-- | arch/sh/mm/extable_64.c | 34 | ||||
-rw-r--r-- | arch/sparc/mm/extable.c | 28 | ||||
-rw-r--r-- | include/linux/extable.h | 5 | ||||
-rw-r--r-- | kernel/extable.c | 3 | ||||
-rw-r--r-- | kernel/module.c | 2 | ||||
-rw-r--r-- | lib/extable.c | 41 |
8 files changed, 63 insertions, 56 deletions
diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c index 94627a3a6a0d..50c020c47e54 100644 --- a/arch/mips/kernel/module.c +++ b/arch/mips/kernel/module.c | |||
@@ -317,7 +317,8 @@ const struct exception_table_entry *search_module_dbetables(unsigned long addr) | |||
317 | 317 | ||
318 | spin_lock_irqsave(&dbe_lock, flags); | 318 | spin_lock_irqsave(&dbe_lock, flags); |
319 | list_for_each_entry(dbe, &dbe_list, dbe_list) { | 319 | list_for_each_entry(dbe, &dbe_list, dbe_list) { |
320 | e = search_extable(dbe->dbe_start, dbe->dbe_end - 1, addr); | 320 | e = search_extable(dbe->dbe_start, |
321 | dbe->dbe_end - dbe->dbe_start, addr); | ||
321 | if (e) | 322 | if (e) |
322 | break; | 323 | break; |
323 | } | 324 | } |
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 38dfa27730ff..b68b4d0726d3 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c | |||
@@ -429,7 +429,8 @@ static const struct exception_table_entry *search_dbe_tables(unsigned long addr) | |||
429 | { | 429 | { |
430 | const struct exception_table_entry *e; | 430 | const struct exception_table_entry *e; |
431 | 431 | ||
432 | e = search_extable(__start___dbe_table, __stop___dbe_table - 1, addr); | 432 | e = search_extable(__start___dbe_table, |
433 | __stop___dbe_table - __start___dbe_table, addr); | ||
433 | if (!e) | 434 | if (!e) |
434 | e = search_module_dbetables(addr); | 435 | e = search_module_dbetables(addr); |
435 | return e; | 436 | return e; |
diff --git a/arch/sh/mm/extable_64.c b/arch/sh/mm/extable_64.c index b90cdfad2c78..7a3b4d33d2e7 100644 --- a/arch/sh/mm/extable_64.c +++ b/arch/sh/mm/extable_64.c | |||
@@ -10,6 +10,7 @@ | |||
10 | * License. See the file "COPYING" in the main directory of this archive | 10 | * License. See the file "COPYING" in the main directory of this archive |
11 | * for more details. | 11 | * for more details. |
12 | */ | 12 | */ |
13 | #include <linux/bsearch.h> | ||
13 | #include <linux/rwsem.h> | 14 | #include <linux/rwsem.h> |
14 | #include <linux/extable.h> | 15 | #include <linux/extable.h> |
15 | #include <linux/uaccess.h> | 16 | #include <linux/uaccess.h> |
@@ -40,10 +41,23 @@ static const struct exception_table_entry *check_exception_ranges(unsigned long | |||
40 | return NULL; | 41 | return NULL; |
41 | } | 42 | } |
42 | 43 | ||
44 | static int cmp_ex_search(const void *key, const void *elt) | ||
45 | { | ||
46 | const struct exception_table_entry *_elt = elt; | ||
47 | unsigned long _key = *(unsigned long *)key; | ||
48 | |||
49 | /* avoid overflow */ | ||
50 | if (_key > _elt->insn) | ||
51 | return 1; | ||
52 | if (_key < _elt->insn) | ||
53 | return -1; | ||
54 | return 0; | ||
55 | } | ||
56 | |||
43 | /* Simple binary search */ | 57 | /* Simple binary search */ |
44 | const struct exception_table_entry * | 58 | const struct exception_table_entry * |
45 | search_extable(const struct exception_table_entry *first, | 59 | search_extable(const struct exception_table_entry *base, |
46 | const struct exception_table_entry *last, | 60 | const size_t num, |
47 | unsigned long value) | 61 | unsigned long value) |
48 | { | 62 | { |
49 | const struct exception_table_entry *mid; | 63 | const struct exception_table_entry *mid; |
@@ -52,20 +66,8 @@ search_extable(const struct exception_table_entry *first, | |||
52 | if (mid) | 66 | if (mid) |
53 | return mid; | 67 | return mid; |
54 | 68 | ||
55 | while (first <= last) { | 69 | return bsearch(&value, base, num, |
56 | long diff; | 70 | sizeof(struct exception_table_entry), cmp_ex_search); |
57 | |||
58 | mid = (last - first) / 2 + first; | ||
59 | diff = mid->insn - value; | ||
60 | if (diff == 0) | ||
61 | return mid; | ||
62 | else if (diff < 0) | ||
63 | first = mid+1; | ||
64 | else | ||
65 | last = mid-1; | ||
66 | } | ||
67 | |||
68 | return NULL; | ||
69 | } | 71 | } |
70 | 72 | ||
71 | int fixup_exception(struct pt_regs *regs) | 73 | int fixup_exception(struct pt_regs *regs) |
diff --git a/arch/sparc/mm/extable.c b/arch/sparc/mm/extable.c index db214e9931d9..2422511dc8c5 100644 --- a/arch/sparc/mm/extable.c +++ b/arch/sparc/mm/extable.c | |||
@@ -13,11 +13,11 @@ void sort_extable(struct exception_table_entry *start, | |||
13 | 13 | ||
14 | /* Caller knows they are in a range if ret->fixup == 0 */ | 14 | /* Caller knows they are in a range if ret->fixup == 0 */ |
15 | const struct exception_table_entry * | 15 | const struct exception_table_entry * |
16 | search_extable(const struct exception_table_entry *start, | 16 | search_extable(const struct exception_table_entry *base, |
17 | const struct exception_table_entry *last, | 17 | const size_t num, |
18 | unsigned long value) | 18 | unsigned long value) |
19 | { | 19 | { |
20 | const struct exception_table_entry *walk; | 20 | int i; |
21 | 21 | ||
22 | /* Single insn entries are encoded as: | 22 | /* Single insn entries are encoded as: |
23 | * word 1: insn address | 23 | * word 1: insn address |
@@ -37,30 +37,30 @@ search_extable(const struct exception_table_entry *start, | |||
37 | */ | 37 | */ |
38 | 38 | ||
39 | /* 1. Try to find an exact match. */ | 39 | /* 1. Try to find an exact match. */ |
40 | for (walk = start; walk <= last; walk++) { | 40 | for (i = 0; i < num; i++) { |
41 | if (walk->fixup == 0) { | 41 | if (base[i].fixup == 0) { |
42 | /* A range entry, skip both parts. */ | 42 | /* A range entry, skip both parts. */ |
43 | walk++; | 43 | i++; |
44 | continue; | 44 | continue; |
45 | } | 45 | } |
46 | 46 | ||
47 | /* A deleted entry; see trim_init_extable */ | 47 | /* A deleted entry; see trim_init_extable */ |
48 | if (walk->fixup == -1) | 48 | if (base[i].fixup == -1) |
49 | continue; | 49 | continue; |
50 | 50 | ||
51 | if (walk->insn == value) | 51 | if (base[i].insn == value) |
52 | return walk; | 52 | return &base[i]; |
53 | } | 53 | } |
54 | 54 | ||
55 | /* 2. Try to find a range match. */ | 55 | /* 2. Try to find a range match. */ |
56 | for (walk = start; walk <= (last - 1); walk++) { | 56 | for (i = 0; i < (num - 1); i++) { |
57 | if (walk->fixup) | 57 | if (base[i].fixup) |
58 | continue; | 58 | continue; |
59 | 59 | ||
60 | if (walk[0].insn <= value && walk[1].insn > value) | 60 | if (base[i].insn <= value && base[i + 1].insn > value) |
61 | return walk; | 61 | return &base[i]; |
62 | 62 | ||
63 | walk++; | 63 | i++; |
64 | } | 64 | } |
65 | 65 | ||
66 | return NULL; | 66 | return NULL; |
diff --git a/include/linux/extable.h b/include/linux/extable.h index 7effea4b257d..28addad0dda7 100644 --- a/include/linux/extable.h +++ b/include/linux/extable.h | |||
@@ -2,13 +2,14 @@ | |||
2 | #define _LINUX_EXTABLE_H | 2 | #define _LINUX_EXTABLE_H |
3 | 3 | ||
4 | #include <linux/stddef.h> /* for NULL */ | 4 | #include <linux/stddef.h> /* for NULL */ |
5 | #include <linux/types.h> | ||
5 | 6 | ||
6 | struct module; | 7 | struct module; |
7 | struct exception_table_entry; | 8 | struct exception_table_entry; |
8 | 9 | ||
9 | const struct exception_table_entry * | 10 | const struct exception_table_entry * |
10 | search_extable(const struct exception_table_entry *first, | 11 | search_extable(const struct exception_table_entry *base, |
11 | const struct exception_table_entry *last, | 12 | const size_t num, |
12 | unsigned long value); | 13 | unsigned long value); |
13 | void sort_extable(struct exception_table_entry *start, | 14 | void sort_extable(struct exception_table_entry *start, |
14 | struct exception_table_entry *finish); | 15 | struct exception_table_entry *finish); |
diff --git a/kernel/extable.c b/kernel/extable.c index 223df4a328a4..38c2412401a1 100644 --- a/kernel/extable.c +++ b/kernel/extable.c | |||
@@ -55,7 +55,8 @@ const struct exception_table_entry *search_exception_tables(unsigned long addr) | |||
55 | { | 55 | { |
56 | const struct exception_table_entry *e; | 56 | const struct exception_table_entry *e; |
57 | 57 | ||
58 | e = search_extable(__start___ex_table, __stop___ex_table-1, addr); | 58 | e = search_extable(__start___ex_table, |
59 | __stop___ex_table - __start___ex_table, addr); | ||
59 | if (!e) | 60 | if (!e) |
60 | e = search_module_extables(addr); | 61 | e = search_module_extables(addr); |
61 | return e; | 62 | return e; |
diff --git a/kernel/module.c b/kernel/module.c index b3dbdde82e80..b0f92a365140 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -4196,7 +4196,7 @@ const struct exception_table_entry *search_module_extables(unsigned long addr) | |||
4196 | goto out; | 4196 | goto out; |
4197 | 4197 | ||
4198 | e = search_extable(mod->extable, | 4198 | e = search_extable(mod->extable, |
4199 | mod->extable + mod->num_exentries - 1, | 4199 | mod->num_exentries, |
4200 | addr); | 4200 | addr); |
4201 | out: | 4201 | out: |
4202 | preempt_enable(); | 4202 | preempt_enable(); |
diff --git a/lib/extable.c b/lib/extable.c index 62968daa66a9..f54996fdd0b8 100644 --- a/lib/extable.c +++ b/lib/extable.c | |||
@@ -9,6 +9,7 @@ | |||
9 | * 2 of the License, or (at your option) any later version. | 9 | * 2 of the License, or (at your option) any later version. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/bsearch.h> | ||
12 | #include <linux/module.h> | 13 | #include <linux/module.h> |
13 | #include <linux/init.h> | 14 | #include <linux/init.h> |
14 | #include <linux/sort.h> | 15 | #include <linux/sort.h> |
@@ -51,7 +52,7 @@ static void swap_ex(void *a, void *b, int size) | |||
51 | * This is used both for the kernel exception table and for | 52 | * This is used both for the kernel exception table and for |
52 | * the exception tables of modules that get loaded. | 53 | * the exception tables of modules that get loaded. |
53 | */ | 54 | */ |
54 | static int cmp_ex(const void *a, const void *b) | 55 | static int cmp_ex_sort(const void *a, const void *b) |
55 | { | 56 | { |
56 | const struct exception_table_entry *x = a, *y = b; | 57 | const struct exception_table_entry *x = a, *y = b; |
57 | 58 | ||
@@ -67,7 +68,7 @@ void sort_extable(struct exception_table_entry *start, | |||
67 | struct exception_table_entry *finish) | 68 | struct exception_table_entry *finish) |
68 | { | 69 | { |
69 | sort(start, finish - start, sizeof(struct exception_table_entry), | 70 | sort(start, finish - start, sizeof(struct exception_table_entry), |
70 | cmp_ex, swap_ex); | 71 | cmp_ex_sort, swap_ex); |
71 | } | 72 | } |
72 | 73 | ||
73 | #ifdef CONFIG_MODULES | 74 | #ifdef CONFIG_MODULES |
@@ -93,6 +94,20 @@ void trim_init_extable(struct module *m) | |||
93 | #endif /* !ARCH_HAS_SORT_EXTABLE */ | 94 | #endif /* !ARCH_HAS_SORT_EXTABLE */ |
94 | 95 | ||
95 | #ifndef ARCH_HAS_SEARCH_EXTABLE | 96 | #ifndef ARCH_HAS_SEARCH_EXTABLE |
97 | |||
98 | static int cmp_ex_search(const void *key, const void *elt) | ||
99 | { | ||
100 | const struct exception_table_entry *_elt = elt; | ||
101 | unsigned long _key = *(unsigned long *)key; | ||
102 | |||
103 | /* avoid overflow */ | ||
104 | if (_key > ex_to_insn(_elt)) | ||
105 | return 1; | ||
106 | if (_key < ex_to_insn(_elt)) | ||
107 | return -1; | ||
108 | return 0; | ||
109 | } | ||
110 | |||
96 | /* | 111 | /* |
97 | * Search one exception table for an entry corresponding to the | 112 | * Search one exception table for an entry corresponding to the |
98 | * given instruction address, and return the address of the entry, | 113 | * given instruction address, and return the address of the entry, |
@@ -101,25 +116,11 @@ void trim_init_extable(struct module *m) | |||
101 | * already sorted. | 116 | * already sorted. |
102 | */ | 117 | */ |
103 | const struct exception_table_entry * | 118 | const struct exception_table_entry * |
104 | search_extable(const struct exception_table_entry *first, | 119 | search_extable(const struct exception_table_entry *base, |
105 | const struct exception_table_entry *last, | 120 | const size_t num, |
106 | unsigned long value) | 121 | unsigned long value) |
107 | { | 122 | { |
108 | while (first <= last) { | 123 | return bsearch(&value, base, num, |
109 | const struct exception_table_entry *mid; | 124 | sizeof(struct exception_table_entry), cmp_ex_search); |
110 | |||
111 | mid = ((last - first) >> 1) + first; | ||
112 | /* | ||
113 | * careful, the distance between value and insn | ||
114 | * can be larger than MAX_LONG: | ||
115 | */ | ||
116 | if (ex_to_insn(mid) < value) | ||
117 | first = mid + 1; | ||
118 | else if (ex_to_insn(mid) > value) | ||
119 | last = mid - 1; | ||
120 | else | ||
121 | return mid; | ||
122 | } | ||
123 | return NULL; | ||
124 | } | 125 | } |
125 | #endif | 126 | #endif |