1 // SPDX-License-Identifier: GPL-2.0 << 2 /* 1 /* 3 * linux/arch/arm/mm/extable.c !! 2 * linux/arch/sparc64/mm/extable.c 4 */ 3 */ 5 #include <linux/extable.h> << 6 #include <linux/uaccess.h> << 7 4 8 int fixup_exception(struct pt_regs *regs) !! 5 #include <linux/config.h> >> 6 #include <linux/module.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 unsigned long >> 13 search_one_table(const struct exception_table_entry *start, >> 14 const struct exception_table_entry *end, >> 15 unsigned long value, unsigned long *g2) 9 { 16 { 10 const struct exception_table_entry *fi !! 17 const struct exception_table_entry *walk; 11 18 12 fixup = search_exception_tables(instru !! 19 /* Single insn entries are encoded as: 13 if (fixup) { !! 20 * word 1: insn address 14 regs->ARM_pc = fixup->fixup; !! 21 * word 2: fixup code address 15 #ifdef CONFIG_THUMB2_KERNEL !! 22 * 16 /* Clear the IT state to avoid !! 23 * Range entries are encoded as: 17 regs->ARM_cpsr &= ~PSR_IT_MASK !! 24 * word 1: first insn address 18 #endif !! 25 * word 2: 0 >> 26 * word 3: last insn address + 4 bytes >> 27 * word 4: fixup code address >> 28 * >> 29 * See asm/uaccess.h for more details. >> 30 */ >> 31 >> 32 /* 1. Try to find an exact match. */ >> 33 for (walk = start; walk <= end; walk++) { >> 34 if (walk->fixup == 0) { >> 35 /* A range entry, skip both parts. */ >> 36 walk++; >> 37 continue; >> 38 } >> 39 >> 40 if (walk->insn == value) >> 41 return walk->fixup; >> 42 } >> 43 >> 44 /* 2. Try to find a range match. */ >> 45 for (walk = start; walk <= (end - 1); walk++) { >> 46 if (walk->fixup) >> 47 continue; >> 48 >> 49 if (walk[0].insn <= value && >> 50 walk[1].insn > value) { >> 51 *g2 = (value - walk[0].insn) / 4; >> 52 return walk[1].fixup; >> 53 } >> 54 walk++; 19 } 55 } 20 56 21 return fixup != NULL; !! 57 return 0; >> 58 } >> 59 >> 60 extern spinlock_t modlist_lock; >> 61 >> 62 unsigned long >> 63 search_exception_table(unsigned long addr, unsigned long *g2) >> 64 { >> 65 unsigned long ret = 0, flags; >> 66 >> 67 #ifndef CONFIG_MODULES >> 68 /* There is only the kernel to search. */ >> 69 ret = search_one_table(__start___ex_table, >> 70 __stop___ex_table-1, addr, g2); >> 71 return ret; >> 72 #else >> 73 /* The kernel is the last "module" -- no need to treat it special. */ >> 74 struct module *mp; >> 75 >> 76 spin_lock_irqsave(&modlist_lock, flags); >> 77 for (mp = module_list; mp != NULL; mp = mp->next) { >> 78 if (mp->ex_table_start == NULL || !(mp->flags & (MOD_RUNNING | MOD_INITIALIZING))) >> 79 continue; >> 80 ret = search_one_table(mp->ex_table_start, >> 81 mp->ex_table_end-1, addr, g2); >> 82 if (ret) >> 83 break; >> 84 } >> 85 spin_unlock_irqrestore(&modlist_lock, flags); >> 86 return ret; >> 87 #endif 22 } 88 } 23 89
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.