2005-04-17 02:20:36 +04:00
/* Rewritten by Rusty Russell, on the backs of many others...
Copyright ( C ) 2001 Rusty Russell , 2002 Rusty Russell IBM .
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
2009-03-20 13:05:04 +03:00
# include <linux/ftrace.h>
2009-03-22 20:11:10 +03:00
# include <linux/memory.h>
2005-04-17 02:20:36 +04:00
# include <linux/module.h>
2009-03-20 13:05:04 +03:00
# include <linux/mutex.h>
2005-04-17 02:20:36 +04:00
# include <linux/init.h>
2009-03-20 13:05:04 +03:00
2005-04-17 02:20:36 +04:00
# include <asm/sections.h>
2009-03-20 13:05:04 +03:00
# include <asm/uaccess.h>
/*
* mutex protecting text section modification ( dynamic code patching ) .
* some users need to sleep ( allocating memory . . . ) while they hold this lock .
*
* NOT exported to modules - patching kernel text is a really delicate matter .
*/
DEFINE_MUTEX ( text_mutex ) ;
2005-04-17 02:20:36 +04:00
extern struct exception_table_entry __start___ex_table [ ] ;
extern struct exception_table_entry __stop___ex_table [ ] ;
/* Sort the kernel's built-in exception table */
void __init sort_main_extable ( void )
{
sort_extable ( __start___ex_table , __stop___ex_table ) ;
}
/* Given an address, look for it in the exception tables. */
const struct exception_table_entry * search_exception_tables ( unsigned long addr )
{
const struct exception_table_entry * e ;
e = search_extable ( __start___ex_table , __stop___ex_table - 1 , addr ) ;
if ( ! e )
e = search_module_extables ( addr ) ;
return e ;
}
2009-03-19 15:21:44 +03:00
static inline int init_kernel_text ( unsigned long addr )
{
if ( addr > = ( unsigned long ) _sinittext & &
addr < = ( unsigned long ) _einittext )
return 1 ;
return 0 ;
}
2009-02-08 02:04:02 +03:00
int core_kernel_text ( unsigned long addr )
2005-04-17 02:20:36 +04:00
{
if ( addr > = ( unsigned long ) _stext & &
addr < = ( unsigned long ) _etext )
return 1 ;
2008-01-30 01:13:17 +03:00
if ( system_state = = SYSTEM_BOOTING & &
2009-03-19 15:21:44 +03:00
init_kernel_text ( addr ) )
2005-04-17 02:20:36 +04:00
return 1 ;
return 0 ;
}
2011-05-20 05:34:58 +04:00
/**
* core_kernel_data - tell if addr points to kernel data
* @ addr : address to test
*
* Returns true if @ addr passed in is from the core kernel data
* section .
*
* Note : On some archs it may return true for core RODATA , and false
* for others . But will always be true for core RW data .
*/
2011-05-06 05:14:55 +04:00
int core_kernel_data ( unsigned long addr )
{
2011-05-20 05:34:58 +04:00
if ( addr > = ( unsigned long ) _sdata & &
2011-05-06 05:14:55 +04:00
addr < ( unsigned long ) _edata )
return 1 ;
return 0 ;
}
2009-02-08 02:04:02 +03:00
int __kernel_text_address ( unsigned long addr )
2005-04-17 02:20:36 +04:00
{
if ( core_kernel_text ( addr ) )
return 1 ;
2009-04-05 21:30:21 +04:00
if ( is_module_text_address ( addr ) )
2009-03-19 15:21:44 +03:00
return 1 ;
/*
* There might be init symbols in saved stacktraces .
* Give those symbols a chance to be printed in
* backtraces ( such as lockdep traces ) .
*
* Since we are after the module - symbols check , there ' s
* no danger of address overlap :
*/
if ( init_kernel_text ( addr ) )
return 1 ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
int kernel_text_address ( unsigned long addr )
{
if ( core_kernel_text ( addr ) )
return 1 ;
2009-03-31 23:05:31 +04:00
return is_module_text_address ( addr ) ;
2005-04-17 02:20:36 +04:00
}
2008-08-16 02:29:38 +04:00
/*
* On some architectures ( PPC64 , IA64 ) function pointers
* are actually only tokens to some data that then holds the
* real function address . As a result , to find if a function
* pointer is part of the kernel text , we need to do some
* special dereferencing first .
*/
int func_ptr_is_kernel_text ( void * ptr )
{
unsigned long addr ;
addr = ( unsigned long ) dereference_function_descriptor ( ptr ) ;
if ( core_kernel_text ( addr ) )
return 1 ;
2009-03-31 23:05:31 +04:00
return is_module_text_address ( addr ) ;
2008-08-16 02:29:38 +04:00
}