diff options
author | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2015-08-05 17:04:01 -0300 |
---|---|---|
committer | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2015-08-05 17:04:01 -0300 |
commit | 57f0f512b273f60d52568b8c6b77e17f5636edc0 (patch) | |
tree | 5e910f0e82173f4ef4f51111366a3f1299037a7b /kernel/extable.c |
Initial import
Diffstat (limited to 'kernel/extable.c')
-rw-r--r-- | kernel/extable.c | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/kernel/extable.c b/kernel/extable.c new file mode 100644 index 000000000..c98f92627 --- /dev/null +++ b/kernel/extable.c @@ -0,0 +1,144 @@ +/* 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 +*/ +#include <linux/ftrace.h> +#include <linux/memory.h> +#include <linux/module.h> +#include <linux/ftrace.h> +#include <linux/mutex.h> +#include <linux/init.h> + +#include <asm/sections.h> +#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); + +extern struct exception_table_entry __start___ex_table[]; +extern struct exception_table_entry __stop___ex_table[]; + +/* Cleared by build time tools if the table is already sorted. */ +u32 __initdata __visible main_extable_sort_needed = 1; + +/* Sort the kernel's built-in exception table */ +void __init sort_main_extable(void) +{ + if (main_extable_sort_needed && __stop___ex_table > __start___ex_table) { + pr_notice("Sorting __ex_table...\n"); + 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; +} + +static inline int init_kernel_text(unsigned long addr) +{ + if (addr >= (unsigned long)_sinittext && + addr < (unsigned long)_einittext) + return 1; + return 0; +} + +int core_kernel_text(unsigned long addr) +{ + if (addr >= (unsigned long)_stext && + addr < (unsigned long)_etext) + return 1; + + if (system_state == SYSTEM_BOOTING && + init_kernel_text(addr)) + return 1; + return 0; +} + +/** + * 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. + */ +int core_kernel_data(unsigned long addr) +{ + if (addr >= (unsigned long)_sdata && + addr < (unsigned long)_edata) + return 1; + return 0; +} + +int __kernel_text_address(unsigned long addr) +{ + if (core_kernel_text(addr)) + return 1; + if (is_module_text_address(addr)) + return 1; + if (is_ftrace_trampoline(addr)) + 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; +} + +int kernel_text_address(unsigned long addr) +{ + if (core_kernel_text(addr)) + return 1; + if (is_module_text_address(addr)) + return 1; + return is_ftrace_trampoline(addr); +} + +/* + * 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; + return is_module_text_address(addr); +} |