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 */ 12 const struct exception_table_entry * 13 search_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 */ 40 static 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 48 void 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 sort(start, finish - start, sizeof(*start), cmp_ex, NULL); 58 /* Denormalize all entries */ 59 for (p = start, i = 0; p < finish; p++, i += 8) 60 p->insn -= i; 61 } 62 63 #ifdef CONFIG_MODULES 64 /* 65 * If the exception table is sorted, any referring to the module init 66 * will be at the beginning or the end. 67 */ 68 void trim_init_extable(struct module *m) 69 { 70 /* Trim the beginning */ 71 while (m->num_exentries && 72 within_module_init(extable_insn(&m->extable[0]), m)) { 73 m->extable++; 74 m->num_exentries--; 75 } 76 /* Trim the end */ 77 while (m->num_exentries && 78 within_module_init(extable_insn(&m->extable[m->num_exentries-1]), m)) 79 m->num_exentries--; 80 } 81 #endif /* CONFIG_MODULES */ 82