diff options
Diffstat (limited to 'kernel/module.c')
-rw-r--r-- | kernel/module.c | 91 |
1 files changed, 87 insertions, 4 deletions
diff --git a/kernel/module.c b/kernel/module.c index e6bc4b28aa62..97f4d5e15535 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -1862,13 +1862,68 @@ static char elf_type(const Elf_Sym *sym, | |||
1862 | return '?'; | 1862 | return '?'; |
1863 | } | 1863 | } |
1864 | 1864 | ||
1865 | static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs, | ||
1866 | unsigned int shnum) | ||
1867 | { | ||
1868 | const Elf_Shdr *sec; | ||
1869 | |||
1870 | if (src->st_shndx == SHN_UNDEF | ||
1871 | || src->st_shndx >= shnum | ||
1872 | || !src->st_name) | ||
1873 | return false; | ||
1874 | |||
1875 | sec = sechdrs + src->st_shndx; | ||
1876 | if (!(sec->sh_flags & SHF_ALLOC) | ||
1877 | #ifndef CONFIG_KALLSYMS_ALL | ||
1878 | || !(sec->sh_flags & SHF_EXECINSTR) | ||
1879 | #endif | ||
1880 | || (sec->sh_entsize & INIT_OFFSET_MASK)) | ||
1881 | return false; | ||
1882 | |||
1883 | return true; | ||
1884 | } | ||
1885 | |||
1886 | static unsigned long layout_symtab(struct module *mod, | ||
1887 | Elf_Shdr *sechdrs, | ||
1888 | unsigned int symindex, | ||
1889 | const Elf_Ehdr *hdr, | ||
1890 | const char *secstrings) | ||
1891 | { | ||
1892 | unsigned long symoffs; | ||
1893 | Elf_Shdr *symsect = sechdrs + symindex; | ||
1894 | const Elf_Sym *src; | ||
1895 | unsigned int i, nsrc, ndst; | ||
1896 | |||
1897 | /* Put symbol section at end of init part of module. */ | ||
1898 | symsect->sh_flags |= SHF_ALLOC; | ||
1899 | symsect->sh_entsize = get_offset(mod, &mod->init_size, symsect, | ||
1900 | symindex) | INIT_OFFSET_MASK; | ||
1901 | DEBUGP("\t%s\n", secstrings + symsect->sh_name); | ||
1902 | |||
1903 | src = (void *)hdr + symsect->sh_offset; | ||
1904 | nsrc = symsect->sh_size / sizeof(*src); | ||
1905 | for (ndst = i = 1; i < nsrc; ++i, ++src) | ||
1906 | if (is_core_symbol(src, sechdrs, hdr->e_shnum)) | ||
1907 | ++ndst; | ||
1908 | |||
1909 | /* Append room for core symbols at end of core part. */ | ||
1910 | symoffs = ALIGN(mod->core_size, symsect->sh_addralign ?: 1); | ||
1911 | mod->core_size = symoffs + ndst * sizeof(Elf_Sym); | ||
1912 | |||
1913 | return symoffs; | ||
1914 | } | ||
1915 | |||
1865 | static void add_kallsyms(struct module *mod, | 1916 | static void add_kallsyms(struct module *mod, |
1866 | Elf_Shdr *sechdrs, | 1917 | Elf_Shdr *sechdrs, |
1918 | unsigned int shnum, | ||
1867 | unsigned int symindex, | 1919 | unsigned int symindex, |
1868 | unsigned int strindex, | 1920 | unsigned int strindex, |
1921 | unsigned long symoffs, | ||
1869 | const char *secstrings) | 1922 | const char *secstrings) |
1870 | { | 1923 | { |
1871 | unsigned int i; | 1924 | unsigned int i, ndst; |
1925 | const Elf_Sym *src; | ||
1926 | Elf_Sym *dst; | ||
1872 | 1927 | ||
1873 | mod->symtab = (void *)sechdrs[symindex].sh_addr; | 1928 | mod->symtab = (void *)sechdrs[symindex].sh_addr; |
1874 | mod->num_symtab = sechdrs[symindex].sh_size / sizeof(Elf_Sym); | 1929 | mod->num_symtab = sechdrs[symindex].sh_size / sizeof(Elf_Sym); |
@@ -1878,12 +1933,32 @@ static void add_kallsyms(struct module *mod, | |||
1878 | for (i = 0; i < mod->num_symtab; i++) | 1933 | for (i = 0; i < mod->num_symtab; i++) |
1879 | mod->symtab[i].st_info | 1934 | mod->symtab[i].st_info |
1880 | = elf_type(&mod->symtab[i], sechdrs, secstrings, mod); | 1935 | = elf_type(&mod->symtab[i], sechdrs, secstrings, mod); |
1936 | |||
1937 | mod->core_symtab = dst = mod->module_core + symoffs; | ||
1938 | src = mod->symtab; | ||
1939 | *dst = *src; | ||
1940 | for (ndst = i = 1; i < mod->num_symtab; ++i, ++src) { | ||
1941 | if (!is_core_symbol(src, sechdrs, shnum)) | ||
1942 | continue; | ||
1943 | dst[ndst] = *src; | ||
1944 | ++ndst; | ||
1945 | } | ||
1946 | mod->core_num_syms = ndst; | ||
1881 | } | 1947 | } |
1882 | #else | 1948 | #else |
1949 | static inline unsigned long layout_symtab(struct module *mod, | ||
1950 | Elf_Shdr *sechdrs, | ||
1951 | unsigned int symindex, | ||
1952 | const Elf_Hdr *hdr, | ||
1953 | const char *secstrings) | ||
1954 | { | ||
1955 | } | ||
1883 | static inline void add_kallsyms(struct module *mod, | 1956 | static inline void add_kallsyms(struct module *mod, |
1884 | Elf_Shdr *sechdrs, | 1957 | Elf_Shdr *sechdrs, |
1958 | unsigned int shnum, | ||
1885 | unsigned int symindex, | 1959 | unsigned int symindex, |
1886 | unsigned int strindex, | 1960 | unsigned int strindex, |
1961 | unsigned long symoffs, | ||
1887 | const char *secstrings) | 1962 | const char *secstrings) |
1888 | { | 1963 | { |
1889 | } | 1964 | } |
@@ -1959,6 +2034,9 @@ static noinline struct module *load_module(void __user *umod, | |||
1959 | struct module *mod; | 2034 | struct module *mod; |
1960 | long err = 0; | 2035 | long err = 0; |
1961 | void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ | 2036 | void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ |
2037 | #ifdef CONFIG_KALLSYMS | ||
2038 | unsigned long symoffs; | ||
2039 | #endif | ||
1962 | mm_segment_t old_fs; | 2040 | mm_segment_t old_fs; |
1963 | 2041 | ||
1964 | DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n", | 2042 | DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n", |
@@ -2041,8 +2119,7 @@ static noinline struct module *load_module(void __user *umod, | |||
2041 | sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC; | 2119 | sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC; |
2042 | sechdrs[versindex].sh_flags &= ~(unsigned long)SHF_ALLOC; | 2120 | sechdrs[versindex].sh_flags &= ~(unsigned long)SHF_ALLOC; |
2043 | #ifdef CONFIG_KALLSYMS | 2121 | #ifdef CONFIG_KALLSYMS |
2044 | /* Keep symbol and string tables for decoding later. */ | 2122 | /* Keep string table for decoding later. */ |
2045 | sechdrs[symindex].sh_flags |= SHF_ALLOC; | ||
2046 | sechdrs[strindex].sh_flags |= SHF_ALLOC; | 2123 | sechdrs[strindex].sh_flags |= SHF_ALLOC; |
2047 | #endif | 2124 | #endif |
2048 | 2125 | ||
@@ -2109,6 +2186,7 @@ static noinline struct module *load_module(void __user *umod, | |||
2109 | this is done generically; there doesn't appear to be any | 2186 | this is done generically; there doesn't appear to be any |
2110 | special cases for the architectures. */ | 2187 | special cases for the architectures. */ |
2111 | layout_sections(mod, hdr, sechdrs, secstrings); | 2188 | layout_sections(mod, hdr, sechdrs, secstrings); |
2189 | symoffs = layout_symtab(mod, sechdrs, symindex, hdr, secstrings); | ||
2112 | 2190 | ||
2113 | /* Do the allocs. */ | 2191 | /* Do the allocs. */ |
2114 | ptr = module_alloc_update_bounds(mod->core_size); | 2192 | ptr = module_alloc_update_bounds(mod->core_size); |
@@ -2313,7 +2391,8 @@ static noinline struct module *load_module(void __user *umod, | |||
2313 | percpu_modcopy(mod->percpu, (void *)sechdrs[pcpuindex].sh_addr, | 2391 | percpu_modcopy(mod->percpu, (void *)sechdrs[pcpuindex].sh_addr, |
2314 | sechdrs[pcpuindex].sh_size); | 2392 | sechdrs[pcpuindex].sh_size); |
2315 | 2393 | ||
2316 | add_kallsyms(mod, sechdrs, symindex, strindex, secstrings); | 2394 | add_kallsyms(mod, sechdrs, hdr->e_shnum, symindex, strindex, |
2395 | symoffs, secstrings); | ||
2317 | 2396 | ||
2318 | if (!mod->taints) { | 2397 | if (!mod->taints) { |
2319 | struct _ddebug *debug; | 2398 | struct _ddebug *debug; |
@@ -2491,6 +2570,10 @@ SYSCALL_DEFINE3(init_module, void __user *, umod, | |||
2491 | /* Drop initial reference. */ | 2570 | /* Drop initial reference. */ |
2492 | module_put(mod); | 2571 | module_put(mod); |
2493 | trim_init_extable(mod); | 2572 | trim_init_extable(mod); |
2573 | #ifdef CONFIG_KALLSYMS | ||
2574 | mod->num_symtab = mod->core_num_syms; | ||
2575 | mod->symtab = mod->core_symtab; | ||
2576 | #endif | ||
2494 | module_free(mod, mod->module_init); | 2577 | module_free(mod, mod->module_init); |
2495 | mod->module_init = NULL; | 2578 | mod->module_init = NULL; |
2496 | mod->init_size = 0; | 2579 | mod->init_size = 0; |