1#include <linux/module.h> 2#include <linux/sort.h> 3#include <asm/uaccess.h> 4 5/* 6 * Search one exception table for an entry corresponding to the 7 * given instruction address, and return the address of the entry, 8 * or NULL if none is found. 9 * We use a binary search, and thus we assume that the table is 10 * already sorted. 11 */ 12const struct exception_table_entry * 13search_extable(const struct exception_table_entry *first, 14 const struct exception_table_entry *last, 15 unsigned long value) 16{ 17 const struct exception_table_entry *mid; 18 unsigned long addr; 19 20 while (first <= last) { 21 mid = ((last - first) >> 1) + first; 22 addr = extable_insn(mid); 23 if (addr < value) 24 first = mid + 1; 25 else if (addr > value) 26 last = mid - 1; 27 else 28 return mid; 29 } 30 return NULL; 31} 32 33/* 34 * The exception table needs to be sorted so that the binary 35 * search that we use to find entries in it works properly. 36 * This is used both for the kernel exception table and for 37 * the exception tables of modules that get loaded. 38 * 39 */ 40static int cmp_ex(const void *a, const void *b) 41{ 42 const struct exception_table_entry *x = a, *y = b; 43 44 /* This compare is only valid after normalization. */ 45 return x->insn - y->insn; 46} 47 48void sort_extable(struct exception_table_entry *start, 49 struct exception_table_entry *finish) 50{ 51 struct exception_table_entry *p; 52 int i; 53 54 /* Normalize entries to being relative to the start of the section */ 55 for (p = start, i = 0; p < finish; p++, i += 8) { 56 p->insn += i; 57 p->fixup += i + 4; 58 } 59 sort(start, finish - start, sizeof(*start), cmp_ex, NULL); 60 /* Denormalize all entries */ 61 for (p = start, i = 0; p < finish; p++, i += 8) { 62 p->insn -= i; 63 p->fixup -= i + 4; 64 } 65} 66 67#ifdef CONFIG_MODULES 68/* 69 * If the exception table is sorted, any referring to the module init 70 * will be at the beginning or the end. 71 */ 72void trim_init_extable(struct module *m) 73{ 74 /* Trim the beginning */ 75 while (m->num_exentries && 76 within_module_init(extable_insn(&m->extable[0]), m)) { 77 m->extable++; 78 m->num_exentries--; 79 } 80 /* Trim the end */ 81 while (m->num_exentries && 82 within_module_init(extable_insn(&m->extable[m->num_exentries-1]), m)) 83 m->num_exentries--; 84} 85#endif /* CONFIG_MODULES */ 86