/*1* Derived from arch/ppc/mm/extable.c and arch/i386/mm/extable.c.2*3* Copyright (C) 2004 Paul Mackerras, IBM Corp.4*5* This program is free software; you can redistribute it and/or6* modify it under the terms of the GNU General Public License7* as published by the Free Software Foundation; either version8* 2 of the License, or (at your option) any later version.9*/1011#include <linux/module.h>12#include <linux/init.h>13#include <linux/sort.h>14#include <asm/uaccess.h>1516#ifndef ARCH_HAS_SORT_EXTABLE17/*18* The exception table needs to be sorted so that the binary19* search that we use to find entries in it works properly.20* This is used both for the kernel exception table and for21* the exception tables of modules that get loaded.22*/23static int cmp_ex(const void *a, const void *b)24{25const struct exception_table_entry *x = a, *y = b;2627/* avoid overflow */28if (x->insn > y->insn)29return 1;30if (x->insn < y->insn)31return -1;32return 0;33}3435void sort_extable(struct exception_table_entry *start,36struct exception_table_entry *finish)37{38sort(start, finish - start, sizeof(struct exception_table_entry),39cmp_ex, NULL);40}4142#ifdef CONFIG_MODULES43/*44* If the exception table is sorted, any referring to the module init45* will be at the beginning or the end.46*/47void trim_init_extable(struct module *m)48{49/*trim the beginning*/50while (m->num_exentries && within_module_init(m->extable[0].insn, m)) {51m->extable++;52m->num_exentries--;53}54/*trim the end*/55while (m->num_exentries &&56within_module_init(m->extable[m->num_exentries-1].insn, m))57m->num_exentries--;58}59#endif /* CONFIG_MODULES */60#endif /* !ARCH_HAS_SORT_EXTABLE */6162#ifndef ARCH_HAS_SEARCH_EXTABLE63/*64* Search one exception table for an entry corresponding to the65* given instruction address, and return the address of the entry,66* or NULL if none is found.67* We use a binary search, and thus we assume that the table is68* already sorted.69*/70const struct exception_table_entry *71search_extable(const struct exception_table_entry *first,72const struct exception_table_entry *last,73unsigned long value)74{75while (first <= last) {76const struct exception_table_entry *mid;7778mid = ((last - first) >> 1) + first;79/*80* careful, the distance between value and insn81* can be larger than MAX_LONG:82*/83if (mid->insn < value)84first = mid + 1;85else if (mid->insn > value)86last = mid - 1;87else88return mid;89}90return NULL;91}92#endif939495