extable cleanup
PATCH 1/1 extable cleanup
Fairly straightforward consolidation of extable handling. Sparc64 is trickiest, with its extable range stuff (ideally, the ranges would be in a separate __extable_range section, then the extable walking code could be made common, too).
Only tested on x86: ppc and sparc64 written untested, others broken.
Feedback & comments welcome!
Rusty.
[ CC'd to SFR as Master Consolidator ]
--
Anyone who quotes me in their sig is an idiot. -- Rusty Russell.
Name: extable cleanup
Author: Rusty Russell
Status: Tested on 2.5.54
Depends: Module/module-license.patch.gz
D: This patch combines the common exception table searching
D: functionality for various architectures, to avoid unneccessary (and
D: currently buggy) duplication, and so that the exception table list
D: and lock can be kept private to module.c.
D:
D: The archs provide "struct exception_table" and "search_extable":
D: the generic infrastructure drives the rest.
kernel/extable.c +7 -35
@@ -16,45 +16,17 @@Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/module.h> -#include <linux/init.h> - -#include <asm/semaphore.h> extern const struct exception_table_entry __start___ex_table[];extern const struct exception_table_entry __stop___ex_table[]; -extern const struct kernel_symbol __start___ksymtab[]; -extern const struct kernel_symbol __stop___ksymtab[]; -extern const struct kernel_symbol __start___gpl_ksymtab[]; -extern const struct kernel_symbol __stop___gpl_ksymtab[]; -/* Protects extables and symbol tables */ -spinlock_t modlist_lock =SPIN_LOCK_UNLOCKED ; - -/* The exception and symbol tables: start with kernel only. */ -LIST_HEAD (extables); -LIST_HEAD (symbols); - -static struct exception_table kernel_extable; -static struct kernel_symbol_group kernel_symbols; -static struct kernel_symbol_group kernel_gpl_symbols; - -void __init extable_init (void ) +/* Given an address, look for it in the exception tables. */ +const struct exception_table_entry *search_exception_tables (unsigned long addr) { -/* Add kernel symbols to symbol table */ - kernel_symbols.num_syms = (__stop___ksymtab - __start___ksymtab); - kernel_symbols.syms = __start___ksymtab; - kernel_symbols.gplonly =0 ; -list_add (&kernel_symbols.list, &symbols); - kernel_gpl_symbols.num_syms = (__stop___gpl_ksymtab - - __start___gpl_ksymtab); - kernel_gpl_symbols.syms = __start___gpl_ksymtab; - kernel_gpl_symbols.gplonly =1 ; -list_add (&kernel_gpl_symbols.list, &symbols); +const struct exception_table_entry *e; -/* Add kernel exception table to exception tables */ - kernel_extable.num_entries = (__stop___ex_table -__start___ex_table); - kernel_extable.entry = __start___ex_table; -list_add (&kernel_extable.list, &extables); + e =search_extable (__start___ex_table, __stop___ex_table-1 , addr); +if (!e) + e =search_module_extables (addr); +return e; } - -
kernel/module.c +55 -1
70 lines not on this page · raw message
include/linux/module.h +19 -4
@@ -43,6 +43,12 @@ struct kernel_symbolextern int init_module (void );extern void cleanup_module (void ); +/* Archs provide a method of finding the correct exception table. */ +const struct exception_table_entry * +search_extable (const struct exception_table_entry *first, +const struct exception_table_entry *last, +unsigned long value); +#ifdef MODULE /* For replacement modutils, use an alias not a pointer. */
@@ -111,6 +117,9 @@ struct kernel_symbol_groupconst struct kernel_symbol *syms; }; +/* Given an address, look for it in the exception tables */ +const struct exception_table_entry *search_exception_tables (unsigned long add); +struct exception_table {struct list_head list;
@@ -300,11 +309,21 @@ const char *module_address_lookup(unsignunsigned long *offset, char **modname); +/* For extable.c to search modules' exception tables. */ +const struct exception_table_entry *search_module_extables (unsigned long addr); +#else /* !CONFIG_MODULES... */ #define EXPORT_SYMBOL (sym)#define EXPORT_SYMBOL_GPL (sym)#define EXPORT_SYMBOL_NOVERS (sym) +/* Given an address, look for it in the exception tables. */ +static inline const struct exception_table_entry * +search_module_extables (unsigned long addr) +{ +return NULL ; +} +/* Get/put a kernel symbol (calls should be symmetric) */ #define symbol_get (x) (&(x))#define symbol_put (x) do { } while(0)
@@ -344,10 +363,6 @@ __attribute__((section(".gnu.linkonce.th#endif /* KBUILD_MODNAME */ #endif /* MODULE */ -/* For archs to search exception tables */ -extern struct list_head extables; -extern spinlock_t modlist_lock; -#define symbol_request (x) try_then_request_module(symbol_get(x), "symbol:" #x)/* BELOW HERE ALL THESE ARE OBSOLETE AND WILL VANISH */
arch/i386/kernel/traps.c +6 -6
@@ -338,7 +338,7 @@ static inline void do_trap(int trapnr, i } kernel_trap: { -unsigned long fixup; +const struct exception_table_entry *fixup;#ifdef CONFIG_PNPBIOS if (unlikely ((regs->xcs |8 ) ==0x88 ))/* 0x80 or 0x88 */ {
@@ -354,9 +354,9 @@ static inline void do_trap(int trapnr, i }#endif - fixup = search_exception_table(regs->eip); + fixup = search_exception_tables(regs->eip);if (fixup) - regs->eip = fixup; + regs->eip = fixup->fixup;else die (str, regs, error_code);return ;
@@ -435,10 +435,10 @@ gp_in_vm86: gp_in_kernel: { -unsigned long fixup; - fixup =search_exception_table (regs->eip); +const struct exception_table_entry *fixup; + fixup =search_exception_tables (regs->eip);if (fixup) { - regs->eip = fixup; + regs->eip = fixup->fixup;return ; }die ("general protection fault" , regs, error_code);
arch/i386/mm/extable.c +7 -41
63 lines not on this page · raw message
arch/i386/mm/fault.c +4 -3
@@ -19,6 +19,7 @@#include <linux/init.h> #include <linux/tty.h> #include <linux/vt_kern.h> /* For unblank_screen() */ +#include <linux/module.h> #include <asm/system.h> #include <asm/uaccess.h>
@@ -154,7 +155,7 @@ asmlinkage void do_page_fault(struct pt_struct vm_area_struct * vma;unsigned long address;unsigned long page; -unsigned long fixup; +const struct exception_table_entry *fixup;int write;siginfo_t info;
@@ -310,8 +311,8 @@ bad_area: no_context:/* Are we prepared to handle this kernel fault? */ -if ((fixup =search_exception_table (regs->eip)) !=0 ) { - regs->eip = fixup; +if ((fixup =search_exception_tables (regs->eip)) !=NULL ) { + regs->eip = fixup->fixup;return ; }
arch/ppc/kernel/traps.c +3 -2
@@ -29,6 +29,7 @@#include <linux/interrupt.h> #include <linux/config.h> #include <linux/init.h> +#include <linux/module.h> #include <asm/pgtable.h> #include <asm/uaccess.h>
@@ -115,7 +116,7 @@ void MachineCheckException(struct pt_regs *regs) {#ifdef CONFIG_ALL_PPC -unsigned long fixup; +const struct exception_table_entry *entry;#endif /* CONFIG_ALL_PPC */ unsigned long msr = regs->msr;
@@ -148,7 +149,7 @@ MachineCheckException(struct pt_regs *re* -- paulus. */ if (((msr &0xffff0000 ) ==0 || (msr & (0x80000 |0x40000 ))) - && (fixup =search_exception_table (regs->nip)) !=0 ) { + && (entry =search_exception_tables (regs->nip)) !=NULL ) {/* * Check that it's a sync instruction, or somewhere * in the twi; isync; nop sequence that inb/inw/inl uses.
arch/ppc/mm/extable.c +9 -37
72 lines not on this page · raw message
arch/ppc/mm/fault.c +4 -4
@@ -27,6 +27,7 @@#include <linux/mm.h> #include <linux/interrupt.h> #include <linux/highmem.h> +#include <linux/module.h> #include <asm/page.h> #include <asm/pgtable.h>
@@ -263,12 +264,11 @@ void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig) { extern void die(const char *,struct pt_regs *,long); - -unsigned long fixup; +const struct exception_table_entry *entry;/* Are we prepared to handle this fault? */ -if ((fixup =search_exception_table (regs->nip)) !=0 ) { - regs->nip = fixup; +if ((entry =search_exception_tables (regs->nip)) !=NULL ) { + regs->nip = entry->fixup;return ; }
arch/sparc64/kernel/traps.c +8 -8
@@ -149,17 +149,17 @@ void data_access_exception (struct pt_reif (regs->tstate &TSTATE_PRIV ) {/* Test if this comes from uaccess places. */ -unsigned long fixup, g2; +const struct exception_table_entry *entry; +unsigned long g2 = regs->u_regs[UREG_G2 ]; - g2 = regs->u_regs[UREG_G2 ]; -if ((fixup =search_exception_table (regs->tpc, &g2))) { +if ((entry =search_extables_range (regs->tpc, &g2))) {/* Ouch, somebody is trying ugly VM hole tricks on us... */ #ifdef DEBUG_EXCEPTIONS printk ("Exception: PC<%016lx> faddr<UNKNOWN>\n" , regs->tpc);printk ("EX_TABLE: insn<%016lx> fixup<%016lx> " -"g2<%016lx>\n" , regs->tpc, fixup, g2); +"g2<%016lx>\n" , regs->tpc, entry->fixup, g2);#endif - regs->tpc = fixup; + regs->tpc = entry->fixup; regs->tnpc = regs->tpc +4 ; regs->u_regs[UREG_G2 ] = g2;return ;
@@ -1370,7 +1370,7 @@ void cheetah_deferred_handler(struct pt_ recoverable =1 ; }else {unsigned long g2 = regs->u_regs[UREG_G2 ]; -unsigned long fixup =search_exception_table (regs->tpc, &g2); +unsigned long fixup =search_extables_range (regs->tpc, &g2);if (fixup !=0UL ) {/* OK, kernel access to userspace. */
@@ -1390,8 +1390,8 @@ void cheetah_deferred_handler(struct pt_/* Only perform fixup if we still have a * recoverable condition. */ -if (fixup !=0UL && recoverable) { - regs->tpc = fixup; +if (entry && recoverable) { + regs->tpc = entry->fixup; regs->tnpc = regs->tpc +4 ; regs->u_regs[UREG_G2 ] = g2; }
arch/sparc64/kernel/unaligned.c +1 -0
@@ -10,6 +10,7 @@#include <linux/kernel.h> #include <linux/sched.h> #include <linux/mm.h> +#include <linux/module.h> #include <asm/asi.h> #include <asm/ptrace.h> #include <asm/pstate.h>
arch/sparc64/mm/extable.c +22 -39
86 lines not on this page · raw message
arch/sparc64/mm/fault.c +2 -1
@@ -14,6 +14,7 @@#include <linux/mman.h> #include <linux/signal.h> #include <linux/mm.h> +#include <linux/module.h> #include <linux/smp_lock.h> #include <linux/init.h> #include <linux/interrupt.h>
@@ -285,7 +286,7 @@ static void do_kernel_fault(struct pt_re/* Look in asi.h: All _S asis have LS bit set */ if ((asi &0x1 ) && - (fixup =search_exception_table (regs->tpc, &g2))) { + (fizup =search_extables_range (regs->tpc, &g2))) { regs->tpc = fixup; regs->tnpc = regs->tpc +4 ; regs->u_regs[UREG_G2 ] = g2;
include/asm-i386/uaccess.h +0 -4
@@ -92,10 +92,6 @@ struct exception_table_entryunsigned long insn, fixup; }; -/* Returns 0 if exception not found and fixup otherwise. */ -extern unsigned long search_exception_table (unsigned long ); - -/* * These are the main single-value transfer routines. They automatically * use the right size if we just have the right pointer type.
include/asm-ppc/uaccess.h +0 -2
@@ -56,8 +56,6 @@ struct exception_table_entryunsigned long insn, fixup; }; -/* Returns 0 if exception not found and fixup otherwise. */ -extern unsigned long search_exception_table (unsigned long );extern void sort_exception_table (void );/*
include/asm-sparc64/uaccess.h +2 -2
@@ -84,8 +84,8 @@ struct exception_table_entryunsigned insn, fixup; }; -/* Returns 0 if exception not found and fixup otherwise. */ -extern unsigned long search_exception_table (unsigned long ,unsigned long *); +/* Special exable search, which handles ranges. Returns fixup */ +unsigned long search_extables_range (unsigned long addr,unsigned long *g2);extern void __ret_efault (void );
init/main.c +0 -2
@@ -61,7 +61,6 @@ extern void init_IRQ(void);extern void init_modules (void );extern void sock_init (void );extern void fork_init (unsigned long ); -extern void extable_init (void );extern void mca_init (void );extern void sbus_init (void );extern void sysctl_init (void );
@@ -391,7 +390,6 @@ asmlinkage void __init start_kernel(void &__stop___param - &__start___param, &unknown_bootoption);trap_init (); -extable_init ();rcu_init ();init_IRQ ();sched_init ();
From: Rusty Russell <[email protected]>
Date: Fri, 03 Jan 2003 19:07:28 +1100
Fairly straightforward consolidation of extable handling. Sparc64 is trickiest, with its extable range stuff (ideally, the ranges would be in a separate __extable_range section, then the extable walking code could be made common, too).
I'm fine with this.
Quoted 7 lines · Rusty Russell
Fairly straightforward consolidation of extable handling. Sparc64 is trickiest, with its extable range stuff (ideally, the ranges would be in a separate
__extable_rangesection, then the extable walking code could be made common, too).Only tested on x86: ppc and sparc64 written untested, others broken.
Did you test on a true i386, which needs exception handling very early on to handle the test for broken WP? In other words, are all the exception table data structures properly initialized?
And did you check that an oops in the init handling works correctly before the kallsyms table has been initialized? That "initcall(symbol_init)" makes me suspect it won't..
There was a reason why "extable_init()" was in init/main.c, and was done _early_.
Linus
In message <[email protected]> you wri te:
Quoted 8 lines · Rusty Russell
Quoted 6 lines
Fairly straightforward consolidation of extable handling. Sparc64 is trickiest, with its extable range stuff (ideally, the ranges would be in a separate
__extable_rangesection, then the extable walking code could be made common, too).
Quoted 5 lines
Quoted 1 line
Only tested on x86: ppc and sparc64 written untested, others broken.
Did you test on a true i386, which needs exception handling very early on to handle the test for broken WP? In other words, are all the exception table data structures properly initialized?
That's not a problem: the exception table search code looks like:
/* 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;
}search_extable is arch specific, and requires no setup on any arch. The list containing the modules is initialized using the LIST_HEAD, so is empty, so search_module_extables is a noop.
Quoted 3 lines
And did you check that an oops in the init handling works correctly before the kallsyms table has been initialized? That "
initcall(symbol_init)" makes me suspect it won't..
Once again, no initialization required. "symbol_init" initializes the EXPORT'ed symbol tables for module loading: kallsyms doesn't need initialization.
Quoted 2 lines
There was a reason why "
extable_init()" was ininit/main.c, and was done _early_.
Yes, because archs iterated through the extable list to find even core kernel exception tables. The patch changes that: the lookup for core kernel is done first, then the module code looks through a linked list, meaning you don't need an extable list for !CONFIG_MODULES, etc.
Hope that clarifies,
Rusty.
--
Anyone who quotes me in their sig is an idiot. -- Rusty Russell.