diff -Nur linux-2.6.0-test9-vanilla/arch/alpha/mm/extable.c linux-2.6.0-test9-modified/arch/alpha/mm/extable.c --- linux-2.6.0-test9-vanilla/arch/alpha/mm/extable.c 2003-10-25 16:42:52.000000000 -0200 +++ linux-2.6.0-test9-modified/arch/alpha/mm/extable.c 2003-11-28 10:43:18.000000000 -0200 @@ -27,3 +27,18 @@ return NULL; } + +/* Exception_table_entry Comparison. Only the field insn is considered. + Results: + equal: 0 + ex1 less than ex2: -1 + ex1 major than ex2: 1 +*/ +int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) { + + if (ex1.insn < ex2.insn) + return(-1); + else if (ex1.insn > ex2.insn) + return(1); + return(0); +} diff -Nur linux-2.6.0-test9-vanilla/arch/arm/mm/extable.c linux-2.6.0-test9-modified/arch/arm/mm/extable.c --- linux-2.6.0-test9-vanilla/arch/arm/mm/extable.c 2003-10-25 16:43:46.000000000 -0200 +++ linux-2.6.0-test9-modified/arch/arm/mm/extable.c 2003-11-28 08:32:44.000000000 -0200 @@ -35,3 +35,19 @@ return fixup != NULL; } + +/* Exception_table_entry Comparison. Only the field insn is considered. + Results: + equal: 0 + ex1 less than ex2: -1 + ex1 major than ex2: 1 + +*/ +int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) { + + if (ex1.insn < ex2.insn) + return(-1); + else if (ex1.insn > ex2.insn) + return(1); + return(0); +} diff -Nur linux-2.6.0-test9-vanilla/arch/arm26/mm/extable.c linux-2.6.0-test9-modified/arch/arm26/mm/extable.c --- linux-2.6.0-test9-vanilla/arch/arm26/mm/extable.c 2003-10-25 16:43:29.000000000 -0200 +++ linux-2.6.0-test9-modified/arch/arm26/mm/extable.c 2003-11-28 08:32:44.000000000 -0200 @@ -38,3 +38,18 @@ return fixup != NULL; } +/* Exception_table_entry Comparison. Only the field insn is considered. + Results: + equal: 0 + ex1 less than ex2: -1 + ex1 major than ex2: 1 + +*/ +int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) { + + if (ex1.insn < ex2.insn) + return(-1); + else if (ex1.insn > ex2.insn) + return(1); + return(0); +} diff -Nur linux-2.6.0-test9-vanilla/arch/cris/mm/extable.c linux-2.6.0-test9-modified/arch/cris/mm/extable.c --- linux-2.6.0-test9-vanilla/arch/cris/mm/extable.c 2003-10-25 16:45:07.000000000 -0200 +++ linux-2.6.0-test9-modified/arch/cris/mm/extable.c 2003-11-28 08:32:44.000000000 -0200 @@ -46,3 +46,19 @@ } return NULL; } + +/* Exception_table_entry Comparison. Only the field insn is considered. + Results: + equal: 0 + ex1 less than ex2: -1 + ex1 major than ex2: 1 + +*/ +int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) { + + if (ex1.insn < ex2.insn) + return(-1); + else if (ex1.insn > ex2.insn) + return(1); + return(0); +} diff -Nur linux-2.6.0-test9-vanilla/arch/h8300/mm/extable.c linux-2.6.0-test9-modified/arch/h8300/mm/extable.c --- linux-2.6.0-test9-vanilla/arch/h8300/mm/extable.c 2003-10-25 16:43:29.000000000 -0200 +++ linux-2.6.0-test9-modified/arch/h8300/mm/extable.c 2003-11-28 08:32:44.000000000 -0200 @@ -28,3 +28,19 @@ } return NULL; } + +/* Exception_table_entry Comparison. Only the field insn is considered. + Results: + equal: 0 + ex1 less than ex2: -1 + ex1 major than ex2: 1 + +*/ +int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) { + + if (ex1.insn < ex2.insn) + return(-1); + else if (ex1.insn > ex2.insn) + return(1); + return(0); +} diff -Nur linux-2.6.0-test9-vanilla/arch/i386/kernel/module.c linux-2.6.0-test9-modified/arch/i386/kernel/module.c --- linux-2.6.0-test9-vanilla/arch/i386/kernel/module.c 2003-10-25 16:43:36.000000000 -0200 +++ linux-2.6.0-test9-modified/arch/i386/kernel/module.c 2003-11-28 10:54:23.725411848 -0200 @@ -21,6 +21,9 @@ #include #include #include +#include +#include +#include #if 0 #define DEBUGP printk @@ -35,13 +38,60 @@ return vmalloc(size); } +/* Verify if the addr belongs to the init section */ +static inline int within_mod_init_section(unsigned long addr, + void *start, unsigned long size) +{ + return ((void *)addr >= start && (void *)addr < start + size); +} + +/* Remove exception table entries that point to init area. + * It will be used in the unload of init section. + */ +void remove_init_exceptions(struct module *mod) { + + static spinlock_t init_ex_remove = SPIN_LOCK_UNLOCKED; + + const struct exception_table_entry *local; + unsigned int i; + int num_init_ex=0; + + + local = mod->extable; + i = 1; + + while (i <= mod->num_exentries) { + if (within_mod_init_section((unsigned long) local->insn, mod->module_init, mod->init_size)) { + num_init_ex++; + } + else break; + local = local+1; + i++; + } + + local = mod->extable; + + /* Move the pointer to remove the init exceptions */ + spin_lock(init_ex_remove); + mod->extable += num_init_ex; + mod->num_exentries -= num_init_ex; + spin_unlock(init_ex_remove); + + /* Unload the init exceptions */ + for(i=0; i < num_init_ex; ++i) + kfree(local+i); +} + /* Free memory returned from module_alloc */ void module_free(struct module *mod, void *module_region) -{ +{ + /* Remove exception entries of the init section */ + if (module_region == mod->module_init) { + remove_init_exceptions(mod); + } + vfree(module_region); - /* FIXME: If module_region == mod->init_region, trim exception - table entries. */ } /* We don't need anything special. */ diff -Nur linux-2.6.0-test9-vanilla/arch/i386/mm/extable.c linux-2.6.0-test9-modified/arch/i386/mm/extable.c --- linux-2.6.0-test9-vanilla/arch/i386/mm/extable.c 2003-10-25 16:44:54.000000000 -0200 +++ linux-2.6.0-test9-modified/arch/i386/mm/extable.c 2003-11-28 10:43:38.000000000 -0200 @@ -56,3 +56,22 @@ return 0; } + +/* Exception_table_entry Comparison. Only the field insn is considered. + Results: + equal: 0 + ex1 less than ex2: -1 + ex1 major than ex2: 1 + +*/ +int extable_cmp(const struct exception_table_entry ex1, + const struct exception_table_entry ex2) +{ + if (ex1.insn < ex2.insn) + return(-1); + else if (ex1.insn > ex2.insn) + return(1); + return(0); +} + + diff -Nur linux-2.6.0-test9-vanilla/arch/ia64/mm/extable.c linux-2.6.0-test9-modified/arch/ia64/mm/extable.c --- linux-2.6.0-test9-vanilla/arch/ia64/mm/extable.c 2003-10-25 16:43:15.000000000 -0200 +++ linux-2.6.0-test9-modified/arch/ia64/mm/extable.c 2003-11-28 08:32:44.000000000 -0200 @@ -44,3 +44,19 @@ regs->cr_iip = fix & ~0xf; ia64_psr(regs)->ri = fix & 0x3; /* set continuation slot number */ } + +/* Exception_table_entry Comparison. Only the field insn is considered. + Results: + equal: 0 + ex1 less than ex2: -1 + ex1 major than ex2: 1 + +*/ +int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) { + + if (ex1.addr < ex2.addr) + return(-1); + else if (ex1.addr > ex2.addr) + return(1); + return(0); +} diff -Nur linux-2.6.0-test9-vanilla/arch/m68k/mm/extable.c linux-2.6.0-test9-modified/arch/m68k/mm/extable.c --- linux-2.6.0-test9-vanilla/arch/m68k/mm/extable.c 2003-10-25 16:44:46.000000000 -0200 +++ linux-2.6.0-test9-modified/arch/m68k/mm/extable.c 2003-11-28 08:32:44.000000000 -0200 @@ -31,3 +31,19 @@ return NULL; } +/* Exception_table_entry Comparison. Only the field insn is considered. + Results: + equal: 0 + ex1 less than ex2: -1 + ex1 major than ex2: 1 + +*/ +int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) { + + if (ex1.insn < ex2.insn) + return(-1); + else if (ex1.insn > ex2.insn) + return(1); + return(0); +} + diff -Nur linux-2.6.0-test9-vanilla/arch/m68knommu/mm/extable.c linux-2.6.0-test9-modified/arch/m68knommu/mm/extable.c --- linux-2.6.0-test9-vanilla/arch/m68knommu/mm/extable.c 2003-10-25 16:43:01.000000000 -0200 +++ linux-2.6.0-test9-modified/arch/m68knommu/mm/extable.c 2003-11-28 08:32:44.000000000 -0200 @@ -28,3 +28,19 @@ } return NULL; } + +/* Exception_table_entry Comparison. Only the field insn is considered. + Results: + equal: 0 + ex1 less than ex2: -1 + ex1 major than ex2: 1 + +*/ +int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) { + + if (ex1.insn < ex2.insn) + return(-1); + else if (ex1.insn > ex2.insn) + return(1); + return(0); +} diff -Nur linux-2.6.0-test9-vanilla/arch/mips/mm/extable.c linux-2.6.0-test9-modified/arch/mips/mm/extable.c --- linux-2.6.0-test9-vanilla/arch/mips/mm/extable.c 2003-10-25 16:43:50.000000000 -0200 +++ linux-2.6.0-test9-modified/arch/mips/mm/extable.c 2003-11-28 08:32:44.000000000 -0200 @@ -28,3 +28,19 @@ } return NULL; } + +/* Exception_table_entry Comparison. Only the field insn is considered. + Results: + equal: 0 + ex1 less than ex2: -1 + ex1 major than ex2: 1 + +*/ +int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) { + + if (ex1.insn < ex2.insn) + return(-1); + else if (ex1.insn > ex2.insn) + return(1); + return(0); +} diff -Nur linux-2.6.0-test9-vanilla/arch/parisc/mm/extable.c linux-2.6.0-test9-modified/arch/parisc/mm/extable.c --- linux-2.6.0-test9-vanilla/arch/parisc/mm/extable.c 2003-10-25 16:43:17.000000000 -0200 +++ linux-2.6.0-test9-modified/arch/parisc/mm/extable.c 2003-11-28 08:32:44.000000000 -0200 @@ -35,3 +35,18 @@ return 0; } +/* Exception_table_entry Comparison. Only the field insn is considered. + Results: + equal: 0 + ex1 less than ex2: -1 + ex1 major than ex2: 1 + +*/ +int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) { + + if (ex1.addr < ex2.addr) + return(-1); + else if (ex1.addr > ex2.addr) + return(1); + return(0); +} diff -Nur linux-2.6.0-test9-vanilla/arch/ppc/mm/extable.c linux-2.6.0-test9-modified/arch/ppc/mm/extable.c --- linux-2.6.0-test9-vanilla/arch/ppc/mm/extable.c 2003-10-25 16:44:43.000000000 -0200 +++ linux-2.6.0-test9-modified/arch/ppc/mm/extable.c 2003-11-28 08:32:44.000000000 -0200 @@ -12,35 +12,6 @@ extern struct exception_table_entry __start___ex_table[]; extern struct exception_table_entry __stop___ex_table[]; -/* - * The exception table needs to be sorted because we use the macros - * which put things into the exception table in a variety of segments - * such as the prep, pmac, chrp, etc. segments as well as the init - * segment and the main kernel text segment. - */ -static inline void -sort_ex_table(struct exception_table_entry *start, - struct exception_table_entry *finish) -{ - struct exception_table_entry el, *p, *q; - - /* insertion sort */ - for (p = start + 1; p < finish; ++p) { - /* start .. p-1 is sorted */ - if (p[0].insn < p[-1].insn) { - /* move element p down to its right place */ - el = *p; - q = p; - do { - /* el comes before q[-1], move q[-1] up one */ - q[0] = q[-1]; - --q; - } while (q > start && el.insn < q[-1].insn); - *q = el; - } - } -} - void __init sort_exception_table(void) { @@ -68,3 +39,19 @@ } return NULL; } + +/* Exception_table_entry Comparison. Only the field insn is considered. + Results: + equal: 0 + ex1 less than ex2: -1 + ex1 major than ex2: 1 + +*/ +int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) { + + if (ex1.insn < ex2.insn) + return(-1); + else if (ex1.insn > ex2.insn) + return(1); + return(0); +} diff -Nur linux-2.6.0-test9-vanilla/arch/ppc64/mm/extable.c linux-2.6.0-test9-modified/arch/ppc64/mm/extable.c --- linux-2.6.0-test9-vanilla/arch/ppc64/mm/extable.c 2003-10-25 16:43:20.000000000 -0200 +++ linux-2.6.0-test9-modified/arch/ppc64/mm/extable.c 2003-11-28 08:32:44.000000000 -0200 @@ -72,3 +72,20 @@ } return NULL; } + +/* Exception_table_entry Comparison. Only the field insn is considered. + Results: + equal: 0 + ex1 less than ex2: -1 + ex1 major than ex2: 1 + +*/ +int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) { + + if (ex1.insn < ex2.insn) + return(-1); + else if (ex1.insn > ex2.insn) + return(1); + return(0); +} + diff -Nur linux-2.6.0-test9-vanilla/arch/s390/mm/extable.c linux-2.6.0-test9-modified/arch/s390/mm/extable.c --- linux-2.6.0-test9-vanilla/arch/s390/mm/extable.c 2003-10-25 16:44:06.000000000 -0200 +++ linux-2.6.0-test9-modified/arch/s390/mm/extable.c 2003-11-28 08:32:44.000000000 -0200 @@ -32,3 +32,19 @@ } return NULL; } + +/* Exception_table_entry Comparison. Only the field insn is considered. + Results: + equal: 0 + ex1 less than ex2: -1 + ex1 major than ex2: 1 + +*/ +int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) { + + if (ex1.insn < ex2.insn) + return(-1); + else if (ex1.insn > ex2.insn) + return(1); + return(0); +} diff -Nur linux-2.6.0-test9-vanilla/arch/sh/mm/extable.c linux-2.6.0-test9-modified/arch/sh/mm/extable.c --- linux-2.6.0-test9-vanilla/arch/sh/mm/extable.c 2003-10-25 16:42:48.000000000 -0200 +++ linux-2.6.0-test9-modified/arch/sh/mm/extable.c 2003-11-28 08:32:44.000000000 -0200 @@ -44,3 +44,19 @@ return 0; } + +/* Exception_table_entry Comparison. Only the field insn is considered. + Results: + equal: 0 + ex1 less than ex2: -1 + ex1 major than ex2: 1 + +*/ +int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) { + + if (ex1.insn < ex2.insn) + return(-1); + else if (ex1.insn > ex2.insn) + return(1); + return(0); +} diff -Nur linux-2.6.0-test9-vanilla/arch/sparc/mm/extable.c linux-2.6.0-test9-modified/arch/sparc/mm/extable.c --- linux-2.6.0-test9-vanilla/arch/sparc/mm/extable.c 2003-10-25 16:43:41.000000000 -0200 +++ linux-2.6.0-test9-modified/arch/sparc/mm/extable.c 2003-11-28 08:32:44.000000000 -0200 @@ -70,3 +70,19 @@ return entry->fixup; } + +/* Exception_table_entry Comparison. Only the field insn is considered. + Results: + equal: 0 + ex1 less than ex2: -1 + ex1 major than ex2: 1 + +*/ +int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) { + + if (ex1.insn < ex2.insn) + return(-1); + else if (ex1.insn > ex2.insn) + return(1); + return(0); +} diff -Nur linux-2.6.0-test9-vanilla/arch/sparc64/mm/extable.c linux-2.6.0-test9-modified/arch/sparc64/mm/extable.c --- linux-2.6.0-test9-vanilla/arch/sparc64/mm/extable.c 2003-10-25 16:43:25.000000000 -0200 +++ linux-2.6.0-test9-modified/arch/sparc64/mm/extable.c 2003-11-28 08:32:44.000000000 -0200 @@ -73,3 +73,20 @@ return entry->fixup; } + +/* Exception_table_entry Comparison. Only the field insn is considered. + Results: + equal: 0 + ex1 less than ex2: -1 + ex1 major than ex2: 1 + +*/ +int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) { + + if (ex1.insn < ex2.insn) + return(-1); + else if (ex1.insn > ex2.insn) + return(1); + return(0); +} + diff -Nur linux-2.6.0-test9-vanilla/arch/x86_64/mm/extable.c linux-2.6.0-test9-modified/arch/x86_64/mm/extable.c --- linux-2.6.0-test9-vanilla/arch/x86_64/mm/extable.c 2003-10-25 16:44:44.000000000 -0200 +++ linux-2.6.0-test9-modified/arch/x86_64/mm/extable.c 2003-11-28 08:32:44.000000000 -0200 @@ -55,3 +55,19 @@ return 0; } core_initcall(check_extable); + +/* Exception_table_entry Comparison. Only the field insn is considered. + Results: + equal: 0 + ex1 less than ex2: -1 + ex1 major than ex2: 1 + +*/ +int extable_cmp(const struct exception_table_entry ex1, const struct exception_table_entry ex2) { + + if (ex1.insn < ex2.insn) + return(-1); + else if (ex1.insn > ex2.insn) + return(1); + return(0); +} diff -Nur linux-2.6.0-test9-vanilla/include/linux/extable.h linux-2.6.0-test9-modified/include/linux/extable.h --- linux-2.6.0-test9-vanilla/include/linux/extable.h 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6.0-test9-modified/include/linux/extable.h 2003-11-28 10:40:57.000000000 -0200 @@ -0,0 +1,51 @@ +#ifndef _EXTABLE_H +#define _EXTABLE_H + +/* + * Functions regarding to exception's table. + * + * * Written by Juliano Silva and Tiago Silva, 2003 + * + **/ + + +#include +#include +#include +#include + +/* Exception_table_entry Comparison. Only the field insn is considered. + * Results: + * equal: 0 + * ex1 less than ex2: -1 + * ex1 major than ex2: 1 + * */ +extern int extable_cmp(struct exception_table_entry ex1, + struct exception_table_entry ex2); + +/* This code sorts an exception table. It is very used with modules code + * void __init_or_module sort_ex_table(struct exception_table_entry *start, + * struct exception_table_entry *finish); + */ +void __init_or_module sort_ex_table(struct exception_table_entry *start, struct exception_table_entry *finish) +{ + struct exception_table_entry el, *p, *q; + + /* insertion sort */ + for (p = start + 1; p < finish; ++p) { + /* start .. p-1 is sorted */ + if (extable_cmp(p[0], p[-1]) == -1) { + /* move element p down to its right place */ + el = *p; + q = p; + do { + /* el comes before q[-1], move q[-1] up one */ + q[0] = q[-1]; + --q; + } while (q > start && extable_cmp(el, q[-1]) == -1); + *q = el; + } + } +} + +#endif diff -Nur linux-2.6.0-test9-vanilla/kernel/module.c linux-2.6.0-test9-modified/kernel/module.c --- linux-2.6.0-test9-vanilla/kernel/module.c 2003-10-25 16:44:09.000000000 -0200 +++ linux-2.6.0-test9-modified/kernel/module.c 2003-11-28 10:41:17.000000000 -0200 @@ -37,6 +37,8 @@ #include #include +#include + #if 0 #define DEBUGP printk #else @@ -1379,6 +1381,7 @@ } #endif + /* Allocate and load the module: note that size of section 0 is always zero, and we rely on this for optional sections. */ static struct module *load_module(void __user *umod, @@ -1615,6 +1618,11 @@ mod->num_exentries = sechdrs[exindex].sh_size / sizeof(*mod->extable); mod->extable = (void *)sechdrs[exindex].sh_addr; + /* Classifying the exception table */ + sort_ex_table((struct exception_table_entry *)mod->extable, + (struct exception_table_entry *)mod->extable + + mod->num_exentries); + /* Now do relocations. */ for (i = 1; i < hdr->e_shnum; i++) { const char *strtab = (char *)sechdrs[strindex].sh_addr;