^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Derived from arch/ppc/mm/extable.c and arch/i386/mm/extable.c.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2004 Paul Mackerras, IBM Corp.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/bsearch.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/sort.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/extable.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #ifndef ARCH_HAS_RELATIVE_EXTABLE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define ex_to_insn(x) ((x)->insn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) static inline unsigned long ex_to_insn(const struct exception_table_entry *x)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) return (unsigned long)&x->insn + x->insn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #ifndef ARCH_HAS_SORT_EXTABLE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #ifndef ARCH_HAS_RELATIVE_EXTABLE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define swap_ex NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static void swap_ex(void *a, void *b, int size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct exception_table_entry *x = a, *y = b, tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) int delta = b - a;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) tmp = *x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) x->insn = y->insn + delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) y->insn = tmp.insn - delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #ifdef swap_ex_entry_fixup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) swap_ex_entry_fixup(x, y, tmp, delta);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) x->fixup = y->fixup + delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) y->fixup = tmp.fixup - delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #endif /* ARCH_HAS_RELATIVE_EXTABLE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * The exception table needs to be sorted so that the binary
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * search that we use to find entries in it works properly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * This is used both for the kernel exception table and for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * the exception tables of modules that get loaded.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) static int cmp_ex_sort(const void *a, const void *b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) const struct exception_table_entry *x = a, *y = b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) /* avoid overflow */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (ex_to_insn(x) > ex_to_insn(y))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (ex_to_insn(x) < ex_to_insn(y))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) void sort_extable(struct exception_table_entry *start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) struct exception_table_entry *finish)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) sort(start, finish - start, sizeof(struct exception_table_entry),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) cmp_ex_sort, swap_ex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #ifdef CONFIG_MODULES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * If the exception table is sorted, any referring to the module init
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * will be at the beginning or the end.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) void trim_init_extable(struct module *m)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) /*trim the beginning*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) while (m->num_exentries &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) within_module_init(ex_to_insn(&m->extable[0]), m)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) m->extable++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) m->num_exentries--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) /*trim the end*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) while (m->num_exentries &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) within_module_init(ex_to_insn(&m->extable[m->num_exentries - 1]),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) m))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) m->num_exentries--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) #endif /* CONFIG_MODULES */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) #endif /* !ARCH_HAS_SORT_EXTABLE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) #ifndef ARCH_HAS_SEARCH_EXTABLE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static int cmp_ex_search(const void *key, const void *elt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) const struct exception_table_entry *_elt = elt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) unsigned long _key = *(unsigned long *)key;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) /* avoid overflow */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) if (_key > ex_to_insn(_elt))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) if (_key < ex_to_insn(_elt))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * Search one exception table for an entry corresponding to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * given instruction address, and return the address of the entry,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * or NULL if none is found.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) * We use a binary search, and thus we assume that the table is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) * already sorted.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) const struct exception_table_entry *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) search_extable(const struct exception_table_entry *base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) const size_t num,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) unsigned long value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) return bsearch(&value, base, num,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) sizeof(struct exception_table_entry), cmp_ex_search);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) #endif