11da177e4SLinus Torvalds /* Rewritten by Rusty Russell, on the backs of many others... 21da177e4SLinus Torvalds Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM. 31da177e4SLinus Torvalds 41da177e4SLinus Torvalds This program is free software; you can redistribute it and/or modify 51da177e4SLinus Torvalds it under the terms of the GNU General Public License as published by 61da177e4SLinus Torvalds the Free Software Foundation; either version 2 of the License, or 71da177e4SLinus Torvalds (at your option) any later version. 81da177e4SLinus Torvalds 91da177e4SLinus Torvalds This program is distributed in the hope that it will be useful, 101da177e4SLinus Torvalds but WITHOUT ANY WARRANTY; without even the implied warranty of 111da177e4SLinus Torvalds MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 121da177e4SLinus Torvalds GNU General Public License for more details. 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds You should have received a copy of the GNU General Public License 151da177e4SLinus Torvalds along with this program; if not, write to the Free Software 161da177e4SLinus Torvalds Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 171da177e4SLinus Torvalds */ 188b96f011SFrederic Weisbecker #include <linux/ftrace.h> 19f80d2d77SDmitri Vorobiev #include <linux/memory.h> 20505f2b97SIngo Molnar #include <linux/module.h> 21505f2b97SIngo Molnar #include <linux/mutex.h> 22505f2b97SIngo Molnar #include <linux/init.h> 23505f2b97SIngo Molnar 241da177e4SLinus Torvalds #include <asm/sections.h> 25505f2b97SIngo Molnar #include <asm/uaccess.h> 26505f2b97SIngo Molnar 27505f2b97SIngo Molnar /* 28505f2b97SIngo Molnar * mutex protecting text section modification (dynamic code patching). 29505f2b97SIngo Molnar * some users need to sleep (allocating memory...) while they hold this lock. 30505f2b97SIngo Molnar * 31505f2b97SIngo Molnar * NOT exported to modules - patching kernel text is a really delicate matter. 32505f2b97SIngo Molnar */ 33505f2b97SIngo Molnar DEFINE_MUTEX(text_mutex); 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds extern struct exception_table_entry __start___ex_table[]; 361da177e4SLinus Torvalds extern struct exception_table_entry __stop___ex_table[]; 371da177e4SLinus Torvalds 38d219e2e8SDavid Daney /* Cleared by build time tools if the table is already sorted. */ 39*00b71030SAndi Kleen u32 __initdata __visible main_extable_sort_needed = 1; 40d219e2e8SDavid Daney 411da177e4SLinus Torvalds /* Sort the kernel's built-in exception table */ 421da177e4SLinus Torvalds void __init sort_main_extable(void) 431da177e4SLinus Torvalds { 44e656a634SUwe Kleine-König if (main_extable_sort_needed && __stop___ex_table > __start___ex_table) { 45bec1b9e7SBorislav Petkov pr_notice("Sorting __ex_table...\n"); 461da177e4SLinus Torvalds sort_extable(__start___ex_table, __stop___ex_table); 47bec1b9e7SBorislav Petkov } 481da177e4SLinus Torvalds } 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds /* Given an address, look for it in the exception tables. */ 511da177e4SLinus Torvalds const struct exception_table_entry *search_exception_tables(unsigned long addr) 521da177e4SLinus Torvalds { 531da177e4SLinus Torvalds const struct exception_table_entry *e; 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds e = search_extable(__start___ex_table, __stop___ex_table-1, addr); 561da177e4SLinus Torvalds if (!e) 571da177e4SLinus Torvalds e = search_module_extables(addr); 581da177e4SLinus Torvalds return e; 591da177e4SLinus Torvalds } 601da177e4SLinus Torvalds 614a44bac1SIngo Molnar static inline int init_kernel_text(unsigned long addr) 624a44bac1SIngo Molnar { 634a44bac1SIngo Molnar if (addr >= (unsigned long)_sinittext && 645ecbe3c3SHelge Deller addr < (unsigned long)_einittext) 654a44bac1SIngo Molnar return 1; 664a44bac1SIngo Molnar return 0; 674a44bac1SIngo Molnar } 684a44bac1SIngo Molnar 693861a17bSFrederic Weisbecker int core_kernel_text(unsigned long addr) 701da177e4SLinus Torvalds { 711da177e4SLinus Torvalds if (addr >= (unsigned long)_stext && 725ecbe3c3SHelge Deller addr < (unsigned long)_etext) 731da177e4SLinus Torvalds return 1; 741da177e4SLinus Torvalds 75a2da4052SRusty Russell if (system_state == SYSTEM_BOOTING && 764a44bac1SIngo Molnar init_kernel_text(addr)) 771da177e4SLinus Torvalds return 1; 781da177e4SLinus Torvalds return 0; 791da177e4SLinus Torvalds } 801da177e4SLinus Torvalds 81a2d063acSSteven Rostedt /** 82a2d063acSSteven Rostedt * core_kernel_data - tell if addr points to kernel data 83a2d063acSSteven Rostedt * @addr: address to test 84a2d063acSSteven Rostedt * 85a2d063acSSteven Rostedt * Returns true if @addr passed in is from the core kernel data 86a2d063acSSteven Rostedt * section. 87a2d063acSSteven Rostedt * 88a2d063acSSteven Rostedt * Note: On some archs it may return true for core RODATA, and false 89a2d063acSSteven Rostedt * for others. But will always be true for core RW data. 90a2d063acSSteven Rostedt */ 91cdbe61bfSSteven Rostedt int core_kernel_data(unsigned long addr) 92cdbe61bfSSteven Rostedt { 93a2d063acSSteven Rostedt if (addr >= (unsigned long)_sdata && 94cdbe61bfSSteven Rostedt addr < (unsigned long)_edata) 95cdbe61bfSSteven Rostedt return 1; 96cdbe61bfSSteven Rostedt return 0; 97cdbe61bfSSteven Rostedt } 98cdbe61bfSSteven Rostedt 993861a17bSFrederic Weisbecker int __kernel_text_address(unsigned long addr) 1001da177e4SLinus Torvalds { 1011da177e4SLinus Torvalds if (core_kernel_text(addr)) 1021da177e4SLinus Torvalds return 1; 103cab4e4c4SLinus Torvalds if (is_module_text_address(addr)) 1044a44bac1SIngo Molnar return 1; 1054a44bac1SIngo Molnar /* 1064a44bac1SIngo Molnar * There might be init symbols in saved stacktraces. 1074a44bac1SIngo Molnar * Give those symbols a chance to be printed in 1084a44bac1SIngo Molnar * backtraces (such as lockdep traces). 1094a44bac1SIngo Molnar * 1104a44bac1SIngo Molnar * Since we are after the module-symbols check, there's 1114a44bac1SIngo Molnar * no danger of address overlap: 1124a44bac1SIngo Molnar */ 1134a44bac1SIngo Molnar if (init_kernel_text(addr)) 1144a44bac1SIngo Molnar return 1; 1154a44bac1SIngo Molnar return 0; 1161da177e4SLinus Torvalds } 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds int kernel_text_address(unsigned long addr) 1191da177e4SLinus Torvalds { 1201da177e4SLinus Torvalds if (core_kernel_text(addr)) 1211da177e4SLinus Torvalds return 1; 122a6e6abd5SRusty Russell return is_module_text_address(addr); 1231da177e4SLinus Torvalds } 124ab7476cfSArjan van de Ven 125ab7476cfSArjan van de Ven /* 126ab7476cfSArjan van de Ven * On some architectures (PPC64, IA64) function pointers 127ab7476cfSArjan van de Ven * are actually only tokens to some data that then holds the 128ab7476cfSArjan van de Ven * real function address. As a result, to find if a function 129ab7476cfSArjan van de Ven * pointer is part of the kernel text, we need to do some 130ab7476cfSArjan van de Ven * special dereferencing first. 131ab7476cfSArjan van de Ven */ 132ab7476cfSArjan van de Ven int func_ptr_is_kernel_text(void *ptr) 133ab7476cfSArjan van de Ven { 134ab7476cfSArjan van de Ven unsigned long addr; 135ab7476cfSArjan van de Ven addr = (unsigned long) dereference_function_descriptor(ptr); 136ab7476cfSArjan van de Ven if (core_kernel_text(addr)) 137ab7476cfSArjan van de Ven return 1; 138a6e6abd5SRusty Russell return is_module_text_address(addr); 139ab7476cfSArjan van de Ven } 140