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 9extern const struct exception_table_entry __start___ex_table[]; 10extern const struct exception_table_entry __stop___ex_table[]; 11 12static inline unsigned long 13search_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 33extern spinlock_t modlist_lock; 34 35unsigned long 36search_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 /* The kernel is the last "module" -- no need to treat it special. */ 47 struct module *mp; 48 49 spin_lock_irqsave(&modlist_lock, flags); 50 for (mp = module_list; mp != NULL; mp = mp->next) { 51 if (mp->ex_table_start == NULL || !(mp->flags&(MOD_RUNNING|MOD_INITIALIZING))) 52 continue; 53 ret = search_one_table(mp->ex_table_start, 54 mp->ex_table_end - 1, addr); 55 if (ret) 56 break; 57 } 58 spin_unlock_irqrestore(&modlist_lock, flags); 59 return ret; 60#endif 61} 62