1 /*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 1994, 1995, 1996, 1999 by Ralf Baechle
7 * Copyright (C) 1999 by Silicon Graphics
8 */
9 #include <linux/config.h>
10 #include <linux/module.h>
11 #include <linux/spinlock.h>
12 #include <asm/uaccess.h>
13
14 extern const struct exception_table_entry __start___ex_table[];
15 extern const struct exception_table_entry __stop___ex_table[];
16
17 static inline unsigned long
search_one_table(const struct exception_table_entry * first,const struct exception_table_entry * last,unsigned long value)18 search_one_table(const struct exception_table_entry *first,
19 const struct exception_table_entry *last,
20 unsigned long value)
21 {
22 while (first <= last) {
23 const struct exception_table_entry *mid;
24 long diff;
25
26 mid = (last - first) / 2 + first;
27 diff = mid->insn - value;
28 if (diff == 0)
29 return mid->nextinsn;
30 else if (diff < 0)
31 first = mid+1;
32 else
33 last = mid-1;
34 }
35 return 0;
36 }
37
38 extern spinlock_t modlist_lock;
39
search_exception_table(unsigned long addr)40 unsigned long search_exception_table(unsigned long addr)
41 {
42 unsigned long ret = 0;
43
44 #ifndef CONFIG_MODULES
45 /* There is only the kernel to search. */
46 ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
47 return ret;
48 #else
49 unsigned long flags;
50 /* The kernel is the last "module" -- no need to treat it special. */
51 struct module *mp;
52
53 spin_lock_irqsave(&modlist_lock, flags);
54 for (mp = module_list; mp != NULL; mp = mp->next) {
55 if (mp->ex_table_start == NULL)
56 continue;
57 ret = search_one_table(mp->ex_table_start,
58 mp->ex_table_end - 1, addr);
59 if (ret)
60 break;
61 }
62 spin_unlock_irqrestore(&modlist_lock, flags);
63 return ret;
64 #endif
65 }
66