Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Derived from arch/ppc/mm/extable.c and arch/i386/mm/extable.c.
0004  *
0005  * Copyright (C) 2004 Paul Mackerras, IBM Corp.
0006  */
0007 
0008 #include <linux/bsearch.h>
0009 #include <linux/module.h>
0010 #include <linux/init.h>
0011 #include <linux/sort.h>
0012 #include <linux/uaccess.h>
0013 #include <linux/extable.h>
0014 
0015 #ifndef ARCH_HAS_RELATIVE_EXTABLE
0016 #define ex_to_insn(x)   ((x)->insn)
0017 #else
0018 static inline unsigned long ex_to_insn(const struct exception_table_entry *x)
0019 {
0020     return (unsigned long)&x->insn + x->insn;
0021 }
0022 #endif
0023 
0024 #ifndef ARCH_HAS_RELATIVE_EXTABLE
0025 #define swap_ex     NULL
0026 #else
0027 static void swap_ex(void *a, void *b, int size)
0028 {
0029     struct exception_table_entry *x = a, *y = b, tmp;
0030     int delta = b - a;
0031 
0032     tmp = *x;
0033     x->insn = y->insn + delta;
0034     y->insn = tmp.insn - delta;
0035 
0036 #ifdef swap_ex_entry_fixup
0037     swap_ex_entry_fixup(x, y, tmp, delta);
0038 #else
0039     x->fixup = y->fixup + delta;
0040     y->fixup = tmp.fixup - delta;
0041 #endif
0042 }
0043 #endif /* ARCH_HAS_RELATIVE_EXTABLE */
0044 
0045 /*
0046  * The exception table needs to be sorted so that the binary
0047  * search that we use to find entries in it works properly.
0048  * This is used both for the kernel exception table and for
0049  * the exception tables of modules that get loaded.
0050  */
0051 static int cmp_ex_sort(const void *a, const void *b)
0052 {
0053     const struct exception_table_entry *x = a, *y = b;
0054 
0055     /* avoid overflow */
0056     if (ex_to_insn(x) > ex_to_insn(y))
0057         return 1;
0058     if (ex_to_insn(x) < ex_to_insn(y))
0059         return -1;
0060     return 0;
0061 }
0062 
0063 void sort_extable(struct exception_table_entry *start,
0064           struct exception_table_entry *finish)
0065 {
0066     sort(start, finish - start, sizeof(struct exception_table_entry),
0067          cmp_ex_sort, swap_ex);
0068 }
0069 
0070 #ifdef CONFIG_MODULES
0071 /*
0072  * If the exception table is sorted, any referring to the module init
0073  * will be at the beginning or the end.
0074  */
0075 void trim_init_extable(struct module *m)
0076 {
0077     /*trim the beginning*/
0078     while (m->num_exentries &&
0079            within_module_init(ex_to_insn(&m->extable[0]), m)) {
0080         m->extable++;
0081         m->num_exentries--;
0082     }
0083     /*trim the end*/
0084     while (m->num_exentries &&
0085            within_module_init(ex_to_insn(&m->extable[m->num_exentries - 1]),
0086                   m))
0087         m->num_exentries--;
0088 }
0089 #endif /* CONFIG_MODULES */
0090 
0091 static int cmp_ex_search(const void *key, const void *elt)
0092 {
0093     const struct exception_table_entry *_elt = elt;
0094     unsigned long _key = *(unsigned long *)key;
0095 
0096     /* avoid overflow */
0097     if (_key > ex_to_insn(_elt))
0098         return 1;
0099     if (_key < ex_to_insn(_elt))
0100         return -1;
0101     return 0;
0102 }
0103 
0104 /*
0105  * Search one exception table for an entry corresponding to the
0106  * given instruction address, and return the address of the entry,
0107  * or NULL if none is found.
0108  * We use a binary search, and thus we assume that the table is
0109  * already sorted.
0110  */
0111 const struct exception_table_entry *
0112 search_extable(const struct exception_table_entry *base,
0113            const size_t num,
0114            unsigned long value)
0115 {
0116     return bsearch(&value, base, num,
0117                sizeof(struct exception_table_entry), cmp_ex_search);
0118 }