2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2005-04-17 02:20:36 +04:00
/*
* Derived from arch / ppc / mm / extable . c and arch / i386 / mm / extable . c .
*
* Copyright ( C ) 2004 Paul Mackerras , IBM Corp .
*/
2017-07-11 01:51:58 +03:00
# include <linux/bsearch.h>
2005-04-17 02:20:36 +04:00
# include <linux/module.h>
# include <linux/init.h>
# include <linux/sort.h>
2016-12-24 22:46:01 +03:00
# include <linux/uaccess.h>
2005-04-17 02:20:36 +04:00
2016-01-01 14:39:09 +03:00
# ifndef ARCH_HAS_RELATIVE_EXTABLE
# define ex_to_insn(x) ((x)->insn)
# else
static inline unsigned long ex_to_insn ( const struct exception_table_entry * x )
{
return ( unsigned long ) & x - > insn + x - > insn ;
}
# endif
2005-04-17 02:20:36 +04:00
# ifndef ARCH_HAS_SORT_EXTABLE
2016-01-01 14:39:09 +03:00
# ifndef ARCH_HAS_RELATIVE_EXTABLE
# define swap_ex NULL
# else
static void swap_ex ( void * a , void * b , int size )
{
struct exception_table_entry * x = a , * y = b , tmp ;
int delta = b - a ;
tmp = * x ;
x - > insn = y - > insn + delta ;
y - > insn = tmp . insn - delta ;
# ifdef swap_ex_entry_fixup
swap_ex_entry_fixup ( x , y , tmp , delta ) ;
# else
x - > fixup = y - > fixup + delta ;
y - > fixup = tmp . fixup - delta ;
# endif
}
# endif /* ARCH_HAS_RELATIVE_EXTABLE */
2005-04-17 02:20:36 +04:00
/*
* The exception table needs to be sorted so that the binary
* search that we use to find entries in it works properly .
* This is used both for the kernel exception table and for
* the exception tables of modules that get loaded .
*/
2017-07-11 01:51:58 +03:00
static int cmp_ex_sort ( const void * a , const void * b )
2005-04-17 02:20:36 +04:00
{
const struct exception_table_entry * x = a , * y = b ;
/* avoid overflow */
2016-01-01 14:39:09 +03:00
if ( ex_to_insn ( x ) > ex_to_insn ( y ) )
2005-04-17 02:20:36 +04:00
return 1 ;
2016-01-01 14:39:09 +03:00
if ( ex_to_insn ( x ) < ex_to_insn ( y ) )
2005-04-17 02:20:36 +04:00
return - 1 ;
return 0 ;
}
void sort_extable ( struct exception_table_entry * start ,
struct exception_table_entry * finish )
{
sort ( start , finish - start , sizeof ( struct exception_table_entry ) ,
2017-07-11 01:51:58 +03:00
cmp_ex_sort , swap_ex ) ;
2005-04-17 02:20:36 +04:00
}
2009-06-13 07:47:03 +04:00
# ifdef CONFIG_MODULES
/*
* If the exception table is sorted , any referring to the module init
* will be at the beginning or the end .
*/
void trim_init_extable ( struct module * m )
{
/*trim the beginning*/
2016-01-01 14:39:09 +03:00
while ( m - > num_exentries & &
within_module_init ( ex_to_insn ( & m - > extable [ 0 ] ) , m ) ) {
2009-06-13 07:47:03 +04:00
m - > extable + + ;
m - > num_exentries - - ;
}
/*trim the end*/
while ( m - > num_exentries & &
2016-01-01 14:39:09 +03:00
within_module_init ( ex_to_insn ( & m - > extable [ m - > num_exentries - 1 ] ) ,
m ) )
2009-06-13 07:47:03 +04:00
m - > num_exentries - - ;
}
# endif /* CONFIG_MODULES */
# endif /* !ARCH_HAS_SORT_EXTABLE */
2005-04-17 02:20:36 +04:00
# ifndef ARCH_HAS_SEARCH_EXTABLE
2017-07-11 01:51:58 +03:00
static int cmp_ex_search ( const void * key , const void * elt )
{
const struct exception_table_entry * _elt = elt ;
unsigned long _key = * ( unsigned long * ) key ;
/* avoid overflow */
if ( _key > ex_to_insn ( _elt ) )
return 1 ;
if ( _key < ex_to_insn ( _elt ) )
return - 1 ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
/*
* Search one exception table for an entry corresponding to the
* given instruction address , and return the address of the entry ,
* or NULL if none is found .
* We use a binary search , and thus we assume that the table is
* already sorted .
*/
const struct exception_table_entry *
2017-07-11 01:51:58 +03:00
search_extable ( const struct exception_table_entry * base ,
const size_t num ,
2005-04-17 02:20:36 +04:00
unsigned long value )
{
2017-07-11 01:51:58 +03:00
return bsearch ( & value , base , num ,
sizeof ( struct exception_table_entry ) , cmp_ex_search ) ;
2005-04-17 02:20:36 +04:00
}
# endif