xref: /openbmc/linux/kernel/extable.c (revision cdbe61bfe70440939e457fb4a8d0995eaaed17de)
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 
381da177e4SLinus Torvalds /* Sort the kernel's built-in exception table */
391da177e4SLinus Torvalds void __init sort_main_extable(void)
401da177e4SLinus Torvalds {
411da177e4SLinus Torvalds 	sort_extable(__start___ex_table, __stop___ex_table);
421da177e4SLinus Torvalds }
431da177e4SLinus Torvalds 
441da177e4SLinus Torvalds /* Given an address, look for it in the exception tables. */
451da177e4SLinus Torvalds const struct exception_table_entry *search_exception_tables(unsigned long addr)
461da177e4SLinus Torvalds {
471da177e4SLinus Torvalds 	const struct exception_table_entry *e;
481da177e4SLinus Torvalds 
491da177e4SLinus Torvalds 	e = search_extable(__start___ex_table, __stop___ex_table-1, addr);
501da177e4SLinus Torvalds 	if (!e)
511da177e4SLinus Torvalds 		e = search_module_extables(addr);
521da177e4SLinus Torvalds 	return e;
531da177e4SLinus Torvalds }
541da177e4SLinus Torvalds 
554a44bac1SIngo Molnar static inline int init_kernel_text(unsigned long addr)
564a44bac1SIngo Molnar {
574a44bac1SIngo Molnar 	if (addr >= (unsigned long)_sinittext &&
584a44bac1SIngo Molnar 	    addr <= (unsigned long)_einittext)
594a44bac1SIngo Molnar 		return 1;
604a44bac1SIngo Molnar 	return 0;
614a44bac1SIngo Molnar }
624a44bac1SIngo Molnar 
633861a17bSFrederic Weisbecker int core_kernel_text(unsigned long addr)
641da177e4SLinus Torvalds {
651da177e4SLinus Torvalds 	if (addr >= (unsigned long)_stext &&
661da177e4SLinus Torvalds 	    addr <= (unsigned long)_etext)
671da177e4SLinus Torvalds 		return 1;
681da177e4SLinus Torvalds 
69a2da4052SRusty Russell 	if (system_state == SYSTEM_BOOTING &&
704a44bac1SIngo Molnar 	    init_kernel_text(addr))
711da177e4SLinus Torvalds 		return 1;
721da177e4SLinus Torvalds 	return 0;
731da177e4SLinus Torvalds }
741da177e4SLinus Torvalds 
75*cdbe61bfSSteven Rostedt int core_kernel_data(unsigned long addr)
76*cdbe61bfSSteven Rostedt {
77*cdbe61bfSSteven Rostedt 	if (addr >= (unsigned long)_sdata &&
78*cdbe61bfSSteven Rostedt 	    addr < (unsigned long)_edata)
79*cdbe61bfSSteven Rostedt 		return 1;
80*cdbe61bfSSteven Rostedt 	return 0;
81*cdbe61bfSSteven Rostedt }
82*cdbe61bfSSteven Rostedt 
833861a17bSFrederic Weisbecker int __kernel_text_address(unsigned long addr)
841da177e4SLinus Torvalds {
851da177e4SLinus Torvalds 	if (core_kernel_text(addr))
861da177e4SLinus Torvalds 		return 1;
87cab4e4c4SLinus Torvalds 	if (is_module_text_address(addr))
884a44bac1SIngo Molnar 		return 1;
894a44bac1SIngo Molnar 	/*
904a44bac1SIngo Molnar 	 * There might be init symbols in saved stacktraces.
914a44bac1SIngo Molnar 	 * Give those symbols a chance to be printed in
924a44bac1SIngo Molnar 	 * backtraces (such as lockdep traces).
934a44bac1SIngo Molnar 	 *
944a44bac1SIngo Molnar 	 * Since we are after the module-symbols check, there's
954a44bac1SIngo Molnar 	 * no danger of address overlap:
964a44bac1SIngo Molnar 	 */
974a44bac1SIngo Molnar 	if (init_kernel_text(addr))
984a44bac1SIngo Molnar 		return 1;
994a44bac1SIngo Molnar 	return 0;
1001da177e4SLinus Torvalds }
1011da177e4SLinus Torvalds 
1021da177e4SLinus Torvalds int kernel_text_address(unsigned long addr)
1031da177e4SLinus Torvalds {
1041da177e4SLinus Torvalds 	if (core_kernel_text(addr))
1051da177e4SLinus Torvalds 		return 1;
106a6e6abd5SRusty Russell 	return is_module_text_address(addr);
1071da177e4SLinus Torvalds }
108ab7476cfSArjan van de Ven 
109ab7476cfSArjan van de Ven /*
110ab7476cfSArjan van de Ven  * On some architectures (PPC64, IA64) function pointers
111ab7476cfSArjan van de Ven  * are actually only tokens to some data that then holds the
112ab7476cfSArjan van de Ven  * real function address. As a result, to find if a function
113ab7476cfSArjan van de Ven  * pointer is part of the kernel text, we need to do some
114ab7476cfSArjan van de Ven  * special dereferencing first.
115ab7476cfSArjan van de Ven  */
116ab7476cfSArjan van de Ven int func_ptr_is_kernel_text(void *ptr)
117ab7476cfSArjan van de Ven {
118ab7476cfSArjan van de Ven 	unsigned long addr;
119ab7476cfSArjan van de Ven 	addr = (unsigned long) dereference_function_descriptor(ptr);
120ab7476cfSArjan van de Ven 	if (core_kernel_text(addr))
121ab7476cfSArjan van de Ven 		return 1;
122a6e6abd5SRusty Russell 	return is_module_text_address(addr);
123ab7476cfSArjan van de Ven }
124