/* Rewritten by Rusty Russell, on the backs of many others...1Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM.23This program is free software; you can redistribute it and/or modify4it under the terms of the GNU General Public License as published by5the Free Software Foundation; either version 2 of the License, or6(at your option) any later version.78This program is distributed in the hope that it will be useful,9but WITHOUT ANY WARRANTY; without even the implied warranty of10MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the11GNU General Public License for more details.1213You should have received a copy of the GNU General Public License14along with this program; if not, write to the Free Software15Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA16*/17#include <linux/ftrace.h>18#include <linux/memory.h>19#include <linux/module.h>20#include <linux/mutex.h>21#include <linux/init.h>2223#include <asm/sections.h>24#include <asm/uaccess.h>2526/*27* mutex protecting text section modification (dynamic code patching).28* some users need to sleep (allocating memory...) while they hold this lock.29*30* NOT exported to modules - patching kernel text is a really delicate matter.31*/32DEFINE_MUTEX(text_mutex);3334extern struct exception_table_entry __start___ex_table[];35extern struct exception_table_entry __stop___ex_table[];3637/* Sort the kernel's built-in exception table */38void __init sort_main_extable(void)39{40sort_extable(__start___ex_table, __stop___ex_table);41}4243/* Given an address, look for it in the exception tables. */44const struct exception_table_entry *search_exception_tables(unsigned long addr)45{46const struct exception_table_entry *e;4748e = search_extable(__start___ex_table, __stop___ex_table-1, addr);49if (!e)50e = search_module_extables(addr);51return e;52}5354static inline int init_kernel_text(unsigned long addr)55{56if (addr >= (unsigned long)_sinittext &&57addr <= (unsigned long)_einittext)58return 1;59return 0;60}6162int core_kernel_text(unsigned long addr)63{64if (addr >= (unsigned long)_stext &&65addr <= (unsigned long)_etext)66return 1;6768if (system_state == SYSTEM_BOOTING &&69init_kernel_text(addr))70return 1;71return 0;72}7374/**75* core_kernel_data - tell if addr points to kernel data76* @addr: address to test77*78* Returns true if @addr passed in is from the core kernel data79* section.80*81* Note: On some archs it may return true for core RODATA, and false82* for others. But will always be true for core RW data.83*/84int core_kernel_data(unsigned long addr)85{86if (addr >= (unsigned long)_sdata &&87addr < (unsigned long)_edata)88return 1;89return 0;90}9192int __kernel_text_address(unsigned long addr)93{94if (core_kernel_text(addr))95return 1;96if (is_module_text_address(addr))97return 1;98/*99* There might be init symbols in saved stacktraces.100* Give those symbols a chance to be printed in101* backtraces (such as lockdep traces).102*103* Since we are after the module-symbols check, there's104* no danger of address overlap:105*/106if (init_kernel_text(addr))107return 1;108return 0;109}110111int kernel_text_address(unsigned long addr)112{113if (core_kernel_text(addr))114return 1;115return is_module_text_address(addr);116}117118/*119* On some architectures (PPC64, IA64) function pointers120* are actually only tokens to some data that then holds the121* real function address. As a result, to find if a function122* pointer is part of the kernel text, we need to do some123* special dereferencing first.124*/125int func_ptr_is_kernel_text(void *ptr)126{127unsigned long addr;128addr = (unsigned long) dereference_function_descriptor(ptr);129if (core_kernel_text(addr))130return 1;131return is_module_text_address(addr);132}133134135