File: /usr/src/linux/arch/mips/mm/extable.c

1     /*
2      * linux/arch/mips/mm/extable.c
3      */
4     #include <linux/config.h>
5     #include <linux/module.h>
6     #include <linux/spinlock.h>
7     #include <asm/uaccess.h>
8     
9     extern const struct exception_table_entry __start___ex_table[];
10     extern const struct exception_table_entry __stop___ex_table[];
11     
12     static inline unsigned long
13     search_one_table(const struct exception_table_entry *first,
14                      const struct exception_table_entry *last,
15                      unsigned long value)
16     {
17     	while (first <= last) {
18     		const struct exception_table_entry *mid;
19     		long diff;
20     
21     		mid = (last - first) / 2 + first;
22     		diff = mid->insn - value;
23     		if (diff == 0)
24     			return mid->nextinsn;
25     		else if (diff < 0)
26     			first = mid+1;
27     		else
28     			last = mid-1;
29     	}
30     	return 0;
31     }
32     
33     extern spinlock_t modlist_lock;
34     
35     unsigned long
36     search_exception_table(unsigned long addr)
37     {
38     	unsigned long ret = 0;
39     	
40     #ifndef CONFIG_MODULES
41     	/* There is only the kernel to search.  */
42     	ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
43     	return ret;
44     #else
45     	unsigned long flags;
46     
47     	/* The kernel is the last "module" -- no need to treat it special.  */
48     	struct module *mp;
49     
50     	spin_lock_irqsave(&modlist_lock, flags);
51     	for (mp = module_list; mp != NULL; mp = mp->next) {
52     		if (mp->ex_table_start == NULL || !(mp->flags&(MOD_RUNNING|MOD_INITIALIZING)))
53     			continue;
54     		ret = search_one_table(mp->ex_table_start,
55     				       mp->ex_table_end - 1, addr);
56     		if (ret)
57     			break;
58     	}
59     	spin_unlock_irqrestore(&modlist_lock, flags);
60     	return ret;
61     #endif
62     }
63