mirror of
https://github.com/torvalds/linux.git
synced 2024-11-15 08:31:55 +00:00
ARM: 9204/2: module: Add all unwind tables when load module
For EABI stack unwinding, when loading .ko module the EXIDX sections will be added to a unwind_table list. However not all EXIDX sections are added because EXIDX sections are searched by hardcoded section names. For functions in other sections such as .ref.text or .kprobes.text, gcc generates seprated EXIDX sections (such as .ARM.exidx.ref.text or .ARM.exidx.kprobes.text). These extra EXIDX sections are not loaded, so when unwinding functions in these sections, we will failed with: unwind: Index not found xxx To fix that, I refactor the code for searching and adding EXIDX sections: - Check section type to search EXIDX tables (0x70000001) instead of strcmp() the hardcoded names. Then find the corresponding text sections by their section names. - Add a unwind_table list in module->arch to save their own unwind_table instead of the fixed-lenth array. - Save .ARM.exidx.init.text section ptr, because it should be cleaned after module init. Now all EXIDX sections of .ko can be added correctly. Signed-off-by: Chen Zhongjin <chenzhongjin@huawei.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
This commit is contained in:
parent
8294fec1ca
commit
b6f21d14f1
@ -3,20 +3,10 @@
|
|||||||
#define _ASM_ARM_MODULE_H
|
#define _ASM_ARM_MODULE_H
|
||||||
|
|
||||||
#include <asm-generic/module.h>
|
#include <asm-generic/module.h>
|
||||||
|
#include <asm/unwind.h>
|
||||||
struct unwind_table;
|
|
||||||
|
|
||||||
#ifdef CONFIG_ARM_UNWIND
|
#ifdef CONFIG_ARM_UNWIND
|
||||||
enum {
|
#define ELF_SECTION_UNWIND 0x70000001
|
||||||
ARM_SEC_INIT,
|
|
||||||
ARM_SEC_DEVINIT,
|
|
||||||
ARM_SEC_CORE,
|
|
||||||
ARM_SEC_EXIT,
|
|
||||||
ARM_SEC_DEVEXIT,
|
|
||||||
ARM_SEC_HOT,
|
|
||||||
ARM_SEC_UNLIKELY,
|
|
||||||
ARM_SEC_MAX,
|
|
||||||
};
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define PLT_ENT_STRIDE L1_CACHE_BYTES
|
#define PLT_ENT_STRIDE L1_CACHE_BYTES
|
||||||
@ -36,7 +26,8 @@ struct mod_plt_sec {
|
|||||||
|
|
||||||
struct mod_arch_specific {
|
struct mod_arch_specific {
|
||||||
#ifdef CONFIG_ARM_UNWIND
|
#ifdef CONFIG_ARM_UNWIND
|
||||||
struct unwind_table *unwind[ARM_SEC_MAX];
|
struct list_head unwind_list;
|
||||||
|
struct unwind_table *init_table;
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_ARM_MODULE_PLTS
|
#ifdef CONFIG_ARM_MODULE_PLTS
|
||||||
struct mod_plt_sec core;
|
struct mod_plt_sec core;
|
||||||
|
@ -24,6 +24,7 @@ struct unwind_idx {
|
|||||||
|
|
||||||
struct unwind_table {
|
struct unwind_table {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
struct list_head mod_list;
|
||||||
const struct unwind_idx *start;
|
const struct unwind_idx *start;
|
||||||
const struct unwind_idx *origin;
|
const struct unwind_idx *origin;
|
||||||
const struct unwind_idx *stop;
|
const struct unwind_idx *stop;
|
||||||
|
@ -459,46 +459,40 @@ int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
|
|||||||
#ifdef CONFIG_ARM_UNWIND
|
#ifdef CONFIG_ARM_UNWIND
|
||||||
const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
|
const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
|
||||||
const Elf_Shdr *sechdrs_end = sechdrs + hdr->e_shnum;
|
const Elf_Shdr *sechdrs_end = sechdrs + hdr->e_shnum;
|
||||||
struct mod_unwind_map maps[ARM_SEC_MAX];
|
struct list_head *unwind_list = &mod->arch.unwind_list;
|
||||||
int i;
|
|
||||||
|
|
||||||
memset(maps, 0, sizeof(maps));
|
INIT_LIST_HEAD(unwind_list);
|
||||||
|
mod->arch.init_table = NULL;
|
||||||
|
|
||||||
for (s = sechdrs; s < sechdrs_end; s++) {
|
for (s = sechdrs; s < sechdrs_end; s++) {
|
||||||
const char *secname = secstrs + s->sh_name;
|
const char *secname = secstrs + s->sh_name;
|
||||||
|
const char *txtname;
|
||||||
|
const Elf_Shdr *txt_sec;
|
||||||
|
|
||||||
if (!(s->sh_flags & SHF_ALLOC))
|
if (!(s->sh_flags & SHF_ALLOC) ||
|
||||||
|
s->sh_type != ELF_SECTION_UNWIND)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (strcmp(".ARM.exidx.init.text", secname) == 0)
|
if (!strcmp(".ARM.exidx", secname))
|
||||||
maps[ARM_SEC_INIT].unw_sec = s;
|
txtname = ".text";
|
||||||
else if (strcmp(".ARM.exidx", secname) == 0)
|
else
|
||||||
maps[ARM_SEC_CORE].unw_sec = s;
|
txtname = secname + strlen(".ARM.exidx");
|
||||||
else if (strcmp(".ARM.exidx.exit.text", secname) == 0)
|
txt_sec = find_mod_section(hdr, sechdrs, txtname);
|
||||||
maps[ARM_SEC_EXIT].unw_sec = s;
|
|
||||||
else if (strcmp(".ARM.exidx.text.unlikely", secname) == 0)
|
|
||||||
maps[ARM_SEC_UNLIKELY].unw_sec = s;
|
|
||||||
else if (strcmp(".ARM.exidx.text.hot", secname) == 0)
|
|
||||||
maps[ARM_SEC_HOT].unw_sec = s;
|
|
||||||
else if (strcmp(".init.text", secname) == 0)
|
|
||||||
maps[ARM_SEC_INIT].txt_sec = s;
|
|
||||||
else if (strcmp(".text", secname) == 0)
|
|
||||||
maps[ARM_SEC_CORE].txt_sec = s;
|
|
||||||
else if (strcmp(".exit.text", secname) == 0)
|
|
||||||
maps[ARM_SEC_EXIT].txt_sec = s;
|
|
||||||
else if (strcmp(".text.unlikely", secname) == 0)
|
|
||||||
maps[ARM_SEC_UNLIKELY].txt_sec = s;
|
|
||||||
else if (strcmp(".text.hot", secname) == 0)
|
|
||||||
maps[ARM_SEC_HOT].txt_sec = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < ARM_SEC_MAX; i++)
|
if (txt_sec) {
|
||||||
if (maps[i].unw_sec && maps[i].txt_sec)
|
struct unwind_table *table =
|
||||||
mod->arch.unwind[i] =
|
unwind_table_add(s->sh_addr,
|
||||||
unwind_table_add(maps[i].unw_sec->sh_addr,
|
s->sh_size,
|
||||||
maps[i].unw_sec->sh_size,
|
txt_sec->sh_addr,
|
||||||
maps[i].txt_sec->sh_addr,
|
txt_sec->sh_size);
|
||||||
maps[i].txt_sec->sh_size);
|
|
||||||
|
list_add(&table->mod_list, unwind_list);
|
||||||
|
|
||||||
|
/* save init table for module_arch_freeing_init */
|
||||||
|
if (strcmp(".ARM.exidx.init.text", secname) == 0)
|
||||||
|
mod->arch.init_table = table;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
|
#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
|
||||||
s = find_mod_section(hdr, sechdrs, ".pv_table");
|
s = find_mod_section(hdr, sechdrs, ".pv_table");
|
||||||
@ -519,19 +513,27 @@ void
|
|||||||
module_arch_cleanup(struct module *mod)
|
module_arch_cleanup(struct module *mod)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_ARM_UNWIND
|
#ifdef CONFIG_ARM_UNWIND
|
||||||
int i;
|
struct unwind_table *tmp;
|
||||||
|
struct unwind_table *n;
|
||||||
|
|
||||||
for (i = 0; i < ARM_SEC_MAX; i++) {
|
list_for_each_entry_safe(tmp, n,
|
||||||
unwind_table_del(mod->arch.unwind[i]);
|
&mod->arch.unwind_list, mod_list) {
|
||||||
mod->arch.unwind[i] = NULL;
|
list_del(&tmp->mod_list);
|
||||||
|
unwind_table_del(tmp);
|
||||||
}
|
}
|
||||||
|
mod->arch.init_table = NULL;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void __weak module_arch_freeing_init(struct module *mod)
|
void __weak module_arch_freeing_init(struct module *mod)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_ARM_UNWIND
|
#ifdef CONFIG_ARM_UNWIND
|
||||||
unwind_table_del(mod->arch.unwind[ARM_SEC_INIT]);
|
struct unwind_table *init = mod->arch.init_table;
|
||||||
mod->arch.unwind[ARM_SEC_INIT] = NULL;
|
|
||||||
|
if (init) {
|
||||||
|
mod->arch.init_table = NULL;
|
||||||
|
list_del(&init->mod_list);
|
||||||
|
unwind_table_del(init);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user