xref: /openbmc/linux/kernel/extable.c (revision cab4e4c43f92582a2bfc026137b3d8a175bd0360)
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 */
181da177e4SLinus Torvalds #include <linux/module.h>
191da177e4SLinus Torvalds #include <linux/init.h>
208b96f011SFrederic Weisbecker #include <linux/ftrace.h>
211da177e4SLinus Torvalds #include <asm/uaccess.h>
221da177e4SLinus Torvalds #include <asm/sections.h>
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds extern struct exception_table_entry __start___ex_table[];
251da177e4SLinus Torvalds extern struct exception_table_entry __stop___ex_table[];
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds /* Sort the kernel's built-in exception table */
281da177e4SLinus Torvalds void __init sort_main_extable(void)
291da177e4SLinus Torvalds {
301da177e4SLinus Torvalds 	sort_extable(__start___ex_table, __stop___ex_table);
311da177e4SLinus Torvalds }
321da177e4SLinus Torvalds 
331da177e4SLinus Torvalds /* Given an address, look for it in the exception tables. */
341da177e4SLinus Torvalds const struct exception_table_entry *search_exception_tables(unsigned long addr)
351da177e4SLinus Torvalds {
361da177e4SLinus Torvalds 	const struct exception_table_entry *e;
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds 	e = search_extable(__start___ex_table, __stop___ex_table-1, addr);
391da177e4SLinus Torvalds 	if (!e)
401da177e4SLinus Torvalds 		e = search_module_extables(addr);
411da177e4SLinus Torvalds 	return e;
421da177e4SLinus Torvalds }
431da177e4SLinus Torvalds 
444a44bac1SIngo Molnar static inline int init_kernel_text(unsigned long addr)
454a44bac1SIngo Molnar {
464a44bac1SIngo Molnar 	if (addr >= (unsigned long)_sinittext &&
474a44bac1SIngo Molnar 	    addr <= (unsigned long)_einittext)
484a44bac1SIngo Molnar 		return 1;
494a44bac1SIngo Molnar 	return 0;
504a44bac1SIngo Molnar }
514a44bac1SIngo Molnar 
528b96f011SFrederic Weisbecker __notrace_funcgraph int core_kernel_text(unsigned long addr)
531da177e4SLinus Torvalds {
541da177e4SLinus Torvalds 	if (addr >= (unsigned long)_stext &&
551da177e4SLinus Torvalds 	    addr <= (unsigned long)_etext)
561da177e4SLinus Torvalds 		return 1;
571da177e4SLinus Torvalds 
58a2da4052SRusty Russell 	if (system_state == SYSTEM_BOOTING &&
594a44bac1SIngo Molnar 	    init_kernel_text(addr))
601da177e4SLinus Torvalds 		return 1;
611da177e4SLinus Torvalds 	return 0;
621da177e4SLinus Torvalds }
631da177e4SLinus Torvalds 
648b96f011SFrederic Weisbecker __notrace_funcgraph int __kernel_text_address(unsigned long addr)
651da177e4SLinus Torvalds {
661da177e4SLinus Torvalds 	if (core_kernel_text(addr))
671da177e4SLinus Torvalds 		return 1;
68*cab4e4c4SLinus Torvalds 	if (is_module_text_address(addr))
694a44bac1SIngo Molnar 		return 1;
704a44bac1SIngo Molnar 	/*
714a44bac1SIngo Molnar 	 * There might be init symbols in saved stacktraces.
724a44bac1SIngo Molnar 	 * Give those symbols a chance to be printed in
734a44bac1SIngo Molnar 	 * backtraces (such as lockdep traces).
744a44bac1SIngo Molnar 	 *
754a44bac1SIngo Molnar 	 * Since we are after the module-symbols check, there's
764a44bac1SIngo Molnar 	 * no danger of address overlap:
774a44bac1SIngo Molnar 	 */
784a44bac1SIngo Molnar 	if (init_kernel_text(addr))
794a44bac1SIngo Molnar 		return 1;
804a44bac1SIngo Molnar 	return 0;
811da177e4SLinus Torvalds }
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds int kernel_text_address(unsigned long addr)
841da177e4SLinus Torvalds {
851da177e4SLinus Torvalds 	if (core_kernel_text(addr))
861da177e4SLinus Torvalds 		return 1;
87a6e6abd5SRusty Russell 	return is_module_text_address(addr);
881da177e4SLinus Torvalds }
89ab7476cfSArjan van de Ven 
90ab7476cfSArjan van de Ven /*
91ab7476cfSArjan van de Ven  * On some architectures (PPC64, IA64) function pointers
92ab7476cfSArjan van de Ven  * are actually only tokens to some data that then holds the
93ab7476cfSArjan van de Ven  * real function address. As a result, to find if a function
94ab7476cfSArjan van de Ven  * pointer is part of the kernel text, we need to do some
95ab7476cfSArjan van de Ven  * special dereferencing first.
96ab7476cfSArjan van de Ven  */
97ab7476cfSArjan van de Ven int func_ptr_is_kernel_text(void *ptr)
98ab7476cfSArjan van de Ven {
99ab7476cfSArjan van de Ven 	unsigned long addr;
100ab7476cfSArjan van de Ven 	addr = (unsigned long) dereference_function_descriptor(ptr);
101ab7476cfSArjan van de Ven 	if (core_kernel_text(addr))
102ab7476cfSArjan van de Ven 		return 1;
103a6e6abd5SRusty Russell 	return is_module_text_address(addr);
104ab7476cfSArjan van de Ven }
105