xref: /openbmc/linux/kernel/extable.c (revision 8a293be0d6fa0720809db6ac35a0552c51710cd2)
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>
20*8a293be0SPaul Gortmaker #include <linux/extable.h>
21505f2b97SIngo Molnar #include <linux/module.h>
22505f2b97SIngo Molnar #include <linux/mutex.h>
23505f2b97SIngo Molnar #include <linux/init.h>
24505f2b97SIngo Molnar 
251da177e4SLinus Torvalds #include <asm/sections.h>
267c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
27505f2b97SIngo Molnar 
28505f2b97SIngo Molnar /*
29505f2b97SIngo Molnar  * mutex protecting text section modification (dynamic code patching).
30505f2b97SIngo Molnar  * some users need to sleep (allocating memory...) while they hold this lock.
31505f2b97SIngo Molnar  *
32505f2b97SIngo Molnar  * NOT exported to modules - patching kernel text is a really delicate matter.
33505f2b97SIngo Molnar  */
34505f2b97SIngo Molnar DEFINE_MUTEX(text_mutex);
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds extern struct exception_table_entry __start___ex_table[];
371da177e4SLinus Torvalds extern struct exception_table_entry __stop___ex_table[];
381da177e4SLinus Torvalds 
39d219e2e8SDavid Daney /* Cleared by build time tools if the table is already sorted. */
4000b71030SAndi Kleen u32 __initdata __visible main_extable_sort_needed = 1;
41d219e2e8SDavid Daney 
421da177e4SLinus Torvalds /* Sort the kernel's built-in exception table */
431da177e4SLinus Torvalds void __init sort_main_extable(void)
441da177e4SLinus Torvalds {
45e656a634SUwe Kleine-König 	if (main_extable_sort_needed && __stop___ex_table > __start___ex_table) {
46bec1b9e7SBorislav Petkov 		pr_notice("Sorting __ex_table...\n");
471da177e4SLinus Torvalds 		sort_extable(__start___ex_table, __stop___ex_table);
48bec1b9e7SBorislav Petkov 	}
491da177e4SLinus Torvalds }
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds /* Given an address, look for it in the exception tables. */
521da177e4SLinus Torvalds const struct exception_table_entry *search_exception_tables(unsigned long addr)
531da177e4SLinus Torvalds {
541da177e4SLinus Torvalds 	const struct exception_table_entry *e;
551da177e4SLinus Torvalds 
561da177e4SLinus Torvalds 	e = search_extable(__start___ex_table, __stop___ex_table-1, addr);
571da177e4SLinus Torvalds 	if (!e)
581da177e4SLinus Torvalds 		e = search_module_extables(addr);
591da177e4SLinus Torvalds 	return e;
601da177e4SLinus Torvalds }
611da177e4SLinus Torvalds 
624a44bac1SIngo Molnar static inline int init_kernel_text(unsigned long addr)
634a44bac1SIngo Molnar {
644a44bac1SIngo Molnar 	if (addr >= (unsigned long)_sinittext &&
655ecbe3c3SHelge Deller 	    addr < (unsigned long)_einittext)
664a44bac1SIngo Molnar 		return 1;
674a44bac1SIngo Molnar 	return 0;
684a44bac1SIngo Molnar }
694a44bac1SIngo Molnar 
703861a17bSFrederic Weisbecker int core_kernel_text(unsigned long addr)
711da177e4SLinus Torvalds {
721da177e4SLinus Torvalds 	if (addr >= (unsigned long)_stext &&
735ecbe3c3SHelge Deller 	    addr < (unsigned long)_etext)
741da177e4SLinus Torvalds 		return 1;
751da177e4SLinus Torvalds 
76a2da4052SRusty Russell 	if (system_state == SYSTEM_BOOTING &&
774a44bac1SIngo Molnar 	    init_kernel_text(addr))
781da177e4SLinus Torvalds 		return 1;
791da177e4SLinus Torvalds 	return 0;
801da177e4SLinus Torvalds }
811da177e4SLinus Torvalds 
82a2d063acSSteven Rostedt /**
83a2d063acSSteven Rostedt  * core_kernel_data - tell if addr points to kernel data
84a2d063acSSteven Rostedt  * @addr: address to test
85a2d063acSSteven Rostedt  *
86a2d063acSSteven Rostedt  * Returns true if @addr passed in is from the core kernel data
87a2d063acSSteven Rostedt  * section.
88a2d063acSSteven Rostedt  *
89a2d063acSSteven Rostedt  * Note: On some archs it may return true for core RODATA, and false
90a2d063acSSteven Rostedt  *  for others. But will always be true for core RW data.
91a2d063acSSteven Rostedt  */
92cdbe61bfSSteven Rostedt int core_kernel_data(unsigned long addr)
93cdbe61bfSSteven Rostedt {
94a2d063acSSteven Rostedt 	if (addr >= (unsigned long)_sdata &&
95cdbe61bfSSteven Rostedt 	    addr < (unsigned long)_edata)
96cdbe61bfSSteven Rostedt 		return 1;
97cdbe61bfSSteven Rostedt 	return 0;
98cdbe61bfSSteven Rostedt }
99cdbe61bfSSteven Rostedt 
1003861a17bSFrederic Weisbecker int __kernel_text_address(unsigned long addr)
1011da177e4SLinus Torvalds {
1021da177e4SLinus Torvalds 	if (core_kernel_text(addr))
1031da177e4SLinus Torvalds 		return 1;
104cab4e4c4SLinus Torvalds 	if (is_module_text_address(addr))
1054a44bac1SIngo Molnar 		return 1;
106aec0be2dSSteven Rostedt (Red Hat) 	if (is_ftrace_trampoline(addr))
107aec0be2dSSteven Rostedt (Red Hat) 		return 1;
1084a44bac1SIngo Molnar 	/*
1094a44bac1SIngo Molnar 	 * There might be init symbols in saved stacktraces.
1104a44bac1SIngo Molnar 	 * Give those symbols a chance to be printed in
1114a44bac1SIngo Molnar 	 * backtraces (such as lockdep traces).
1124a44bac1SIngo Molnar 	 *
1134a44bac1SIngo Molnar 	 * Since we are after the module-symbols check, there's
1144a44bac1SIngo Molnar 	 * no danger of address overlap:
1154a44bac1SIngo Molnar 	 */
1164a44bac1SIngo Molnar 	if (init_kernel_text(addr))
1174a44bac1SIngo Molnar 		return 1;
1184a44bac1SIngo Molnar 	return 0;
1191da177e4SLinus Torvalds }
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds int kernel_text_address(unsigned long addr)
1221da177e4SLinus Torvalds {
1231da177e4SLinus Torvalds 	if (core_kernel_text(addr))
1241da177e4SLinus Torvalds 		return 1;
125aec0be2dSSteven Rostedt (Red Hat) 	if (is_module_text_address(addr))
126aec0be2dSSteven Rostedt (Red Hat) 		return 1;
127aec0be2dSSteven Rostedt (Red Hat) 	return is_ftrace_trampoline(addr);
1281da177e4SLinus Torvalds }
129ab7476cfSArjan van de Ven 
130ab7476cfSArjan van de Ven /*
131ab7476cfSArjan van de Ven  * On some architectures (PPC64, IA64) function pointers
132ab7476cfSArjan van de Ven  * are actually only tokens to some data that then holds the
133ab7476cfSArjan van de Ven  * real function address. As a result, to find if a function
134ab7476cfSArjan van de Ven  * pointer is part of the kernel text, we need to do some
135ab7476cfSArjan van de Ven  * special dereferencing first.
136ab7476cfSArjan van de Ven  */
137ab7476cfSArjan van de Ven int func_ptr_is_kernel_text(void *ptr)
138ab7476cfSArjan van de Ven {
139ab7476cfSArjan van de Ven 	unsigned long addr;
140ab7476cfSArjan van de Ven 	addr = (unsigned long) dereference_function_descriptor(ptr);
141ab7476cfSArjan van de Ven 	if (core_kernel_text(addr))
142ab7476cfSArjan van de Ven 		return 1;
143a6e6abd5SRusty Russell 	return is_module_text_address(addr);
144ab7476cfSArjan van de Ven }
145