1/* 2 * linux/arch/sparc/mm/extable.c 3 */ 4 5#include <linux/module.h> 6#include <asm/uaccess.h> 7 8void sort_extable(struct exception_table_entry *start, 9 struct exception_table_entry *finish) 10{ 11} 12 13/* Caller knows they are in a range if ret->fixup == 0 */ 14const struct exception_table_entry * 15search_extable(const struct exception_table_entry *start, 16 const struct exception_table_entry *last, 17 unsigned long value) 18{ 19 const struct exception_table_entry *walk; 20 21 /* Single insn entries are encoded as: 22 * word 1: insn address 23 * word 2: fixup code address 24 * 25 * Range entries are encoded as: 26 * word 1: first insn address 27 * word 2: 0 28 * word 3: last insn address + 4 bytes 29 * word 4: fixup code address 30 * 31 * Deleted entries are encoded as: 32 * word 1: unused 33 * word 2: -1 34 * 35 * See asm/uaccess.h for more details. 36 */ 37 38 /* 1. Try to find an exact match. */ 39 for (walk = start; walk <= last; walk++) { 40 if (walk->fixup == 0) { 41 /* A range entry, skip both parts. */ 42 walk++; 43 continue; 44 } 45 46 /* A deleted entry; see trim_init_extable */ 47 if (walk->fixup == -1) 48 continue; 49 50 if (walk->insn == value) 51 return walk; 52 } 53 54 /* 2. Try to find a range match. */ 55 for (walk = start; walk <= (last - 1); walk++) { 56 if (walk->fixup) 57 continue; 58 59 if (walk[0].insn <= value && walk[1].insn > value) 60 return walk; 61 62 walk++; 63 } 64 65 return NULL; 66} 67 68#ifdef CONFIG_MODULES 69/* We could memmove them around; easier to mark the trimmed ones. */ 70void trim_init_extable(struct module *m) 71{ 72 unsigned int i; 73 bool range; 74 75 for (i = 0; i < m->num_exentries; i += range ? 2 : 1) { 76 range = m->extable[i].fixup == 0; 77 78 if (within_module_init(m->extable[i].insn, m)) { 79 m->extable[i].fixup = -1; 80 if (range) 81 m->extable[i+1].fixup = -1; 82 } 83 if (range) 84 i++; 85 } 86} 87#endif /* CONFIG_MODULES */ 88 89/* Special extable search, which handles ranges. Returns fixup */ 90unsigned long search_extables_range(unsigned long addr, unsigned long *g2) 91{ 92 const struct exception_table_entry *entry; 93 94 entry = search_exception_tables(addr); 95 if (!entry) 96 return 0; 97 98 /* Inside range? Fix g2 and return correct fixup */ 99 if (!entry->fixup) { 100 *g2 = (addr - entry->insn) / 4; 101 return (entry + 1)->fixup; 102 } 103 104 return entry->fixup; 105} 106