diff options
Diffstat (limited to 'kernel/module.c')
-rw-r--r-- | kernel/module.c | 166 |
1 files changed, 141 insertions, 25 deletions
diff --git a/kernel/module.c b/kernel/module.c index bbe04862e1b0..2a19cd47c046 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* Rewritten by Rusty Russell, on the backs of many others... | 1 | /* |
2 | Copyright (C) 2002 Richard Henderson | 2 | Copyright (C) 2002 Richard Henderson |
3 | Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM. | 3 | Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM. |
4 | 4 | ||
@@ -16,7 +16,6 @@ | |||
16 | along with this program; if not, write to the Free Software | 16 | along with this program; if not, write to the Free Software |
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 | */ | 18 | */ |
19 | #include <linux/config.h> | ||
20 | #include <linux/module.h> | 19 | #include <linux/module.h> |
21 | #include <linux/moduleloader.h> | 20 | #include <linux/moduleloader.h> |
22 | #include <linux/init.h> | 21 | #include <linux/init.h> |
@@ -40,9 +39,11 @@ | |||
40 | #include <linux/string.h> | 39 | #include <linux/string.h> |
41 | #include <linux/sched.h> | 40 | #include <linux/sched.h> |
42 | #include <linux/mutex.h> | 41 | #include <linux/mutex.h> |
42 | #include <linux/unwind.h> | ||
43 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
44 | #include <asm/semaphore.h> | 44 | #include <asm/semaphore.h> |
45 | #include <asm/cacheflush.h> | 45 | #include <asm/cacheflush.h> |
46 | #include <linux/license.h> | ||
46 | 47 | ||
47 | #if 0 | 48 | #if 0 |
48 | #define DEBUGP printk | 49 | #define DEBUGP printk |
@@ -120,9 +121,17 @@ extern const struct kernel_symbol __start___ksymtab_gpl[]; | |||
120 | extern const struct kernel_symbol __stop___ksymtab_gpl[]; | 121 | extern const struct kernel_symbol __stop___ksymtab_gpl[]; |
121 | extern const struct kernel_symbol __start___ksymtab_gpl_future[]; | 122 | extern const struct kernel_symbol __start___ksymtab_gpl_future[]; |
122 | extern const struct kernel_symbol __stop___ksymtab_gpl_future[]; | 123 | extern const struct kernel_symbol __stop___ksymtab_gpl_future[]; |
124 | extern const struct kernel_symbol __start___ksymtab_unused[]; | ||
125 | extern const struct kernel_symbol __stop___ksymtab_unused[]; | ||
126 | extern const struct kernel_symbol __start___ksymtab_unused_gpl[]; | ||
127 | extern const struct kernel_symbol __stop___ksymtab_unused_gpl[]; | ||
128 | extern const struct kernel_symbol __start___ksymtab_gpl_future[]; | ||
129 | extern const struct kernel_symbol __stop___ksymtab_gpl_future[]; | ||
123 | extern const unsigned long __start___kcrctab[]; | 130 | extern const unsigned long __start___kcrctab[]; |
124 | extern const unsigned long __start___kcrctab_gpl[]; | 131 | extern const unsigned long __start___kcrctab_gpl[]; |
125 | extern const unsigned long __start___kcrctab_gpl_future[]; | 132 | extern const unsigned long __start___kcrctab_gpl_future[]; |
133 | extern const unsigned long __start___kcrctab_unused[]; | ||
134 | extern const unsigned long __start___kcrctab_unused_gpl[]; | ||
126 | 135 | ||
127 | #ifndef CONFIG_MODVERSIONS | 136 | #ifndef CONFIG_MODVERSIONS |
128 | #define symversion(base, idx) NULL | 137 | #define symversion(base, idx) NULL |
@@ -142,6 +151,17 @@ static const struct kernel_symbol *lookup_symbol(const char *name, | |||
142 | return NULL; | 151 | return NULL; |
143 | } | 152 | } |
144 | 153 | ||
154 | static void printk_unused_warning(const char *name) | ||
155 | { | ||
156 | printk(KERN_WARNING "Symbol %s is marked as UNUSED, " | ||
157 | "however this module is using it.\n", name); | ||
158 | printk(KERN_WARNING "This symbol will go away in the future.\n"); | ||
159 | printk(KERN_WARNING "Please evalute if this is the right api to use, " | ||
160 | "and if it really is, submit a report the linux kernel " | ||
161 | "mailinglist together with submitting your code for " | ||
162 | "inclusion.\n"); | ||
163 | } | ||
164 | |||
145 | /* Find a symbol, return value, crc and module which owns it */ | 165 | /* Find a symbol, return value, crc and module which owns it */ |
146 | static unsigned long __find_symbol(const char *name, | 166 | static unsigned long __find_symbol(const char *name, |
147 | struct module **owner, | 167 | struct module **owner, |
@@ -184,6 +204,25 @@ static unsigned long __find_symbol(const char *name, | |||
184 | return ks->value; | 204 | return ks->value; |
185 | } | 205 | } |
186 | 206 | ||
207 | ks = lookup_symbol(name, __start___ksymtab_unused, | ||
208 | __stop___ksymtab_unused); | ||
209 | if (ks) { | ||
210 | printk_unused_warning(name); | ||
211 | *crc = symversion(__start___kcrctab_unused, | ||
212 | (ks - __start___ksymtab_unused)); | ||
213 | return ks->value; | ||
214 | } | ||
215 | |||
216 | if (gplok) | ||
217 | ks = lookup_symbol(name, __start___ksymtab_unused_gpl, | ||
218 | __stop___ksymtab_unused_gpl); | ||
219 | if (ks) { | ||
220 | printk_unused_warning(name); | ||
221 | *crc = symversion(__start___kcrctab_unused_gpl, | ||
222 | (ks - __start___ksymtab_unused_gpl)); | ||
223 | return ks->value; | ||
224 | } | ||
225 | |||
187 | /* Now try modules. */ | 226 | /* Now try modules. */ |
188 | list_for_each_entry(mod, &modules, list) { | 227 | list_for_each_entry(mod, &modules, list) { |
189 | *owner = mod; | 228 | *owner = mod; |
@@ -202,6 +241,23 @@ static unsigned long __find_symbol(const char *name, | |||
202 | return ks->value; | 241 | return ks->value; |
203 | } | 242 | } |
204 | } | 243 | } |
244 | ks = lookup_symbol(name, mod->unused_syms, mod->unused_syms + mod->num_unused_syms); | ||
245 | if (ks) { | ||
246 | printk_unused_warning(name); | ||
247 | *crc = symversion(mod->unused_crcs, (ks - mod->unused_syms)); | ||
248 | return ks->value; | ||
249 | } | ||
250 | |||
251 | if (gplok) { | ||
252 | ks = lookup_symbol(name, mod->unused_gpl_syms, | ||
253 | mod->unused_gpl_syms + mod->num_unused_gpl_syms); | ||
254 | if (ks) { | ||
255 | printk_unused_warning(name); | ||
256 | *crc = symversion(mod->unused_gpl_crcs, | ||
257 | (ks - mod->unused_gpl_syms)); | ||
258 | return ks->value; | ||
259 | } | ||
260 | } | ||
205 | ks = lookup_symbol(name, mod->gpl_future_syms, | 261 | ks = lookup_symbol(name, mod->gpl_future_syms, |
206 | (mod->gpl_future_syms + | 262 | (mod->gpl_future_syms + |
207 | mod->num_gpl_future_syms)); | 263 | mod->num_gpl_future_syms)); |
@@ -1051,6 +1107,8 @@ static void free_module(struct module *mod) | |||
1051 | remove_sect_attrs(mod); | 1107 | remove_sect_attrs(mod); |
1052 | mod_kobject_remove(mod); | 1108 | mod_kobject_remove(mod); |
1053 | 1109 | ||
1110 | unwind_remove_table(mod->unwind_info, 0); | ||
1111 | |||
1054 | /* Arch-specific cleanup. */ | 1112 | /* Arch-specific cleanup. */ |
1055 | module_arch_cleanup(mod); | 1113 | module_arch_cleanup(mod); |
1056 | 1114 | ||
@@ -1063,6 +1121,9 @@ static void free_module(struct module *mod) | |||
1063 | if (mod->percpu) | 1121 | if (mod->percpu) |
1064 | percpu_modfree(mod->percpu); | 1122 | percpu_modfree(mod->percpu); |
1065 | 1123 | ||
1124 | /* Free lock-classes: */ | ||
1125 | lockdep_free_key_range(mod->module_core, mod->core_size); | ||
1126 | |||
1066 | /* Finally, free the core (containing the module structure) */ | 1127 | /* Finally, free the core (containing the module structure) */ |
1067 | module_free(mod, mod->module_core); | 1128 | module_free(mod, mod->module_core); |
1068 | } | 1129 | } |
@@ -1248,16 +1309,6 @@ static void layout_sections(struct module *mod, | |||
1248 | } | 1309 | } |
1249 | } | 1310 | } |
1250 | 1311 | ||
1251 | static inline int license_is_gpl_compatible(const char *license) | ||
1252 | { | ||
1253 | return (strcmp(license, "GPL") == 0 | ||
1254 | || strcmp(license, "GPL v2") == 0 | ||
1255 | || strcmp(license, "GPL and additional rights") == 0 | ||
1256 | || strcmp(license, "Dual BSD/GPL") == 0 | ||
1257 | || strcmp(license, "Dual MIT/GPL") == 0 | ||
1258 | || strcmp(license, "Dual MPL/GPL") == 0); | ||
1259 | } | ||
1260 | |||
1261 | static void set_license(struct module *mod, const char *license) | 1312 | static void set_license(struct module *mod, const char *license) |
1262 | { | 1313 | { |
1263 | if (!license) | 1314 | if (!license) |
@@ -1326,7 +1377,7 @@ int is_exported(const char *name, const struct module *mod) | |||
1326 | if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab)) | 1377 | if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab)) |
1327 | return 1; | 1378 | return 1; |
1328 | else | 1379 | else |
1329 | if (lookup_symbol(name, mod->syms, mod->syms + mod->num_syms)) | 1380 | if (mod && lookup_symbol(name, mod->syms, mod->syms + mod->num_syms)) |
1330 | return 1; | 1381 | return 1; |
1331 | else | 1382 | else |
1332 | return 0; | 1383 | return 0; |
@@ -1409,10 +1460,27 @@ static struct module *load_module(void __user *umod, | |||
1409 | Elf_Ehdr *hdr; | 1460 | Elf_Ehdr *hdr; |
1410 | Elf_Shdr *sechdrs; | 1461 | Elf_Shdr *sechdrs; |
1411 | char *secstrings, *args, *modmagic, *strtab = NULL; | 1462 | char *secstrings, *args, *modmagic, *strtab = NULL; |
1412 | unsigned int i, symindex = 0, strindex = 0, setupindex, exindex, | 1463 | unsigned int i; |
1413 | exportindex, modindex, obsparmindex, infoindex, gplindex, | 1464 | unsigned int symindex = 0; |
1414 | crcindex, gplcrcindex, versindex, pcpuindex, gplfutureindex, | 1465 | unsigned int strindex = 0; |
1415 | gplfuturecrcindex; | 1466 | unsigned int setupindex; |
1467 | unsigned int exindex; | ||
1468 | unsigned int exportindex; | ||
1469 | unsigned int modindex; | ||
1470 | unsigned int obsparmindex; | ||
1471 | unsigned int infoindex; | ||
1472 | unsigned int gplindex; | ||
1473 | unsigned int crcindex; | ||
1474 | unsigned int gplcrcindex; | ||
1475 | unsigned int versindex; | ||
1476 | unsigned int pcpuindex; | ||
1477 | unsigned int gplfutureindex; | ||
1478 | unsigned int gplfuturecrcindex; | ||
1479 | unsigned int unwindex = 0; | ||
1480 | unsigned int unusedindex; | ||
1481 | unsigned int unusedcrcindex; | ||
1482 | unsigned int unusedgplindex; | ||
1483 | unsigned int unusedgplcrcindex; | ||
1416 | struct module *mod; | 1484 | struct module *mod; |
1417 | long err = 0; | 1485 | long err = 0; |
1418 | void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ | 1486 | void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ |
@@ -1493,15 +1561,22 @@ static struct module *load_module(void __user *umod, | |||
1493 | exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab"); | 1561 | exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab"); |
1494 | gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl"); | 1562 | gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl"); |
1495 | gplfutureindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl_future"); | 1563 | gplfutureindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl_future"); |
1564 | unusedindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused"); | ||
1565 | unusedgplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused_gpl"); | ||
1496 | crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab"); | 1566 | crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab"); |
1497 | gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl"); | 1567 | gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl"); |
1498 | gplfuturecrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl_future"); | 1568 | gplfuturecrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl_future"); |
1569 | unusedcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused"); | ||
1570 | unusedgplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused_gpl"); | ||
1499 | setupindex = find_sec(hdr, sechdrs, secstrings, "__param"); | 1571 | setupindex = find_sec(hdr, sechdrs, secstrings, "__param"); |
1500 | exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table"); | 1572 | exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table"); |
1501 | obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm"); | 1573 | obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm"); |
1502 | versindex = find_sec(hdr, sechdrs, secstrings, "__versions"); | 1574 | versindex = find_sec(hdr, sechdrs, secstrings, "__versions"); |
1503 | infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo"); | 1575 | infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo"); |
1504 | pcpuindex = find_pcpusec(hdr, sechdrs, secstrings); | 1576 | pcpuindex = find_pcpusec(hdr, sechdrs, secstrings); |
1577 | #ifdef ARCH_UNWIND_SECTION_NAME | ||
1578 | unwindex = find_sec(hdr, sechdrs, secstrings, ARCH_UNWIND_SECTION_NAME); | ||
1579 | #endif | ||
1505 | 1580 | ||
1506 | /* Don't keep modinfo section */ | 1581 | /* Don't keep modinfo section */ |
1507 | sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC; | 1582 | sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC; |
@@ -1510,6 +1585,8 @@ static struct module *load_module(void __user *umod, | |||
1510 | sechdrs[symindex].sh_flags |= SHF_ALLOC; | 1585 | sechdrs[symindex].sh_flags |= SHF_ALLOC; |
1511 | sechdrs[strindex].sh_flags |= SHF_ALLOC; | 1586 | sechdrs[strindex].sh_flags |= SHF_ALLOC; |
1512 | #endif | 1587 | #endif |
1588 | if (unwindex) | ||
1589 | sechdrs[unwindex].sh_flags |= SHF_ALLOC; | ||
1513 | 1590 | ||
1514 | /* Check module struct version now, before we try to use module. */ | 1591 | /* Check module struct version now, before we try to use module. */ |
1515 | if (!check_modstruct_version(sechdrs, versindex, mod)) { | 1592 | if (!check_modstruct_version(sechdrs, versindex, mod)) { |
@@ -1639,14 +1716,27 @@ static struct module *load_module(void __user *umod, | |||
1639 | mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr; | 1716 | mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr; |
1640 | mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size / | 1717 | mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size / |
1641 | sizeof(*mod->gpl_future_syms); | 1718 | sizeof(*mod->gpl_future_syms); |
1719 | mod->num_unused_syms = sechdrs[unusedindex].sh_size / | ||
1720 | sizeof(*mod->unused_syms); | ||
1721 | mod->num_unused_gpl_syms = sechdrs[unusedgplindex].sh_size / | ||
1722 | sizeof(*mod->unused_gpl_syms); | ||
1642 | mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr; | 1723 | mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr; |
1643 | if (gplfuturecrcindex) | 1724 | if (gplfuturecrcindex) |
1644 | mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr; | 1725 | mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr; |
1645 | 1726 | ||
1727 | mod->unused_syms = (void *)sechdrs[unusedindex].sh_addr; | ||
1728 | if (unusedcrcindex) | ||
1729 | mod->unused_crcs = (void *)sechdrs[unusedcrcindex].sh_addr; | ||
1730 | mod->unused_gpl_syms = (void *)sechdrs[unusedgplindex].sh_addr; | ||
1731 | if (unusedgplcrcindex) | ||
1732 | mod->unused_crcs = (void *)sechdrs[unusedgplcrcindex].sh_addr; | ||
1733 | |||
1646 | #ifdef CONFIG_MODVERSIONS | 1734 | #ifdef CONFIG_MODVERSIONS |
1647 | if ((mod->num_syms && !crcindex) || | 1735 | if ((mod->num_syms && !crcindex) || |
1648 | (mod->num_gpl_syms && !gplcrcindex) || | 1736 | (mod->num_gpl_syms && !gplcrcindex) || |
1649 | (mod->num_gpl_future_syms && !gplfuturecrcindex)) { | 1737 | (mod->num_gpl_future_syms && !gplfuturecrcindex) || |
1738 | (mod->num_unused_syms && !unusedcrcindex) || | ||
1739 | (mod->num_unused_gpl_syms && !unusedgplcrcindex)) { | ||
1650 | printk(KERN_WARNING "%s: No versions for exported symbols." | 1740 | printk(KERN_WARNING "%s: No versions for exported symbols." |
1651 | " Tainting kernel.\n", mod->name); | 1741 | " Tainting kernel.\n", mod->name); |
1652 | add_taint(TAINT_FORCED_MODULE); | 1742 | add_taint(TAINT_FORCED_MODULE); |
@@ -1738,6 +1828,11 @@ static struct module *load_module(void __user *umod, | |||
1738 | goto arch_cleanup; | 1828 | goto arch_cleanup; |
1739 | add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs); | 1829 | add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs); |
1740 | 1830 | ||
1831 | /* Size of section 0 is 0, so this works well if no unwind info. */ | ||
1832 | mod->unwind_info = unwind_add_table(mod, | ||
1833 | (void *)sechdrs[unwindex].sh_addr, | ||
1834 | sechdrs[unwindex].sh_size); | ||
1835 | |||
1741 | /* Get rid of temporary copy */ | 1836 | /* Get rid of temporary copy */ |
1742 | vfree(hdr); | 1837 | vfree(hdr); |
1743 | 1838 | ||
@@ -1836,6 +1931,7 @@ sys_init_module(void __user *umod, | |||
1836 | mod->state = MODULE_STATE_LIVE; | 1931 | mod->state = MODULE_STATE_LIVE; |
1837 | /* Drop initial reference. */ | 1932 | /* Drop initial reference. */ |
1838 | module_put(mod); | 1933 | module_put(mod); |
1934 | unwind_remove_table(mod->unwind_info, 1); | ||
1839 | module_free(mod, mod->module_init); | 1935 | module_free(mod, mod->module_init); |
1840 | mod->module_init = NULL; | 1936 | mod->module_init = NULL; |
1841 | mod->init_size = 0; | 1937 | mod->init_size = 0; |
@@ -1923,10 +2019,8 @@ const char *module_address_lookup(unsigned long addr, | |||
1923 | return NULL; | 2019 | return NULL; |
1924 | } | 2020 | } |
1925 | 2021 | ||
1926 | struct module *module_get_kallsym(unsigned int symnum, | 2022 | struct module *module_get_kallsym(unsigned int symnum, unsigned long *value, |
1927 | unsigned long *value, | 2023 | char *type, char *name, size_t namelen) |
1928 | char *type, | ||
1929 | char namebuf[128]) | ||
1930 | { | 2024 | { |
1931 | struct module *mod; | 2025 | struct module *mod; |
1932 | 2026 | ||
@@ -1935,9 +2029,8 @@ struct module *module_get_kallsym(unsigned int symnum, | |||
1935 | if (symnum < mod->num_symtab) { | 2029 | if (symnum < mod->num_symtab) { |
1936 | *value = mod->symtab[symnum].st_value; | 2030 | *value = mod->symtab[symnum].st_value; |
1937 | *type = mod->symtab[symnum].st_info; | 2031 | *type = mod->symtab[symnum].st_info; |
1938 | strncpy(namebuf, | 2032 | strlcpy(name, mod->strtab + mod->symtab[symnum].st_name, |
1939 | mod->strtab + mod->symtab[symnum].st_name, | 2033 | namelen); |
1940 | 127); | ||
1941 | mutex_unlock(&module_mutex); | 2034 | mutex_unlock(&module_mutex); |
1942 | return mod; | 2035 | return mod; |
1943 | } | 2036 | } |
@@ -2066,6 +2159,29 @@ const struct exception_table_entry *search_module_extables(unsigned long addr) | |||
2066 | return e; | 2159 | return e; |
2067 | } | 2160 | } |
2068 | 2161 | ||
2162 | /* | ||
2163 | * Is this a valid module address? | ||
2164 | */ | ||
2165 | int is_module_address(unsigned long addr) | ||
2166 | { | ||
2167 | unsigned long flags; | ||
2168 | struct module *mod; | ||
2169 | |||
2170 | spin_lock_irqsave(&modlist_lock, flags); | ||
2171 | |||
2172 | list_for_each_entry(mod, &modules, list) { | ||
2173 | if (within(addr, mod->module_core, mod->core_size)) { | ||
2174 | spin_unlock_irqrestore(&modlist_lock, flags); | ||
2175 | return 1; | ||
2176 | } | ||
2177 | } | ||
2178 | |||
2179 | spin_unlock_irqrestore(&modlist_lock, flags); | ||
2180 | |||
2181 | return 0; | ||
2182 | } | ||
2183 | |||
2184 | |||
2069 | /* Is this a valid kernel address? We don't grab the lock: we are oopsing. */ | 2185 | /* Is this a valid kernel address? We don't grab the lock: we are oopsing. */ |
2070 | struct module *__module_text_address(unsigned long addr) | 2186 | struct module *__module_text_address(unsigned long addr) |
2071 | { | 2187 | { |