Skip to content

Commit b6f21d1

Browse files
Chen ZhongjinRussell King (Oracle)
authored andcommitted
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>
1 parent 8294fec commit b6f21d1

File tree

3 files changed

+45
-51
lines changed

3 files changed

+45
-51
lines changed

arch/arm/include/asm/module.h

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,10 @@
33
#define _ASM_ARM_MODULE_H
44

55
#include <asm-generic/module.h>
6-
7-
struct unwind_table;
6+
#include <asm/unwind.h>
87

98
#ifdef CONFIG_ARM_UNWIND
10-
enum {
11-
ARM_SEC_INIT,
12-
ARM_SEC_DEVINIT,
13-
ARM_SEC_CORE,
14-
ARM_SEC_EXIT,
15-
ARM_SEC_DEVEXIT,
16-
ARM_SEC_HOT,
17-
ARM_SEC_UNLIKELY,
18-
ARM_SEC_MAX,
19-
};
9+
#define ELF_SECTION_UNWIND 0x70000001
2010
#endif
2111

2212
#define PLT_ENT_STRIDE L1_CACHE_BYTES
@@ -36,7 +26,8 @@ struct mod_plt_sec {
3626

3727
struct mod_arch_specific {
3828
#ifdef CONFIG_ARM_UNWIND
39-
struct unwind_table *unwind[ARM_SEC_MAX];
29+
struct list_head unwind_list;
30+
struct unwind_table *init_table;
4031
#endif
4132
#ifdef CONFIG_ARM_MODULE_PLTS
4233
struct mod_plt_sec core;

arch/arm/include/asm/unwind.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ struct unwind_idx {
2424

2525
struct unwind_table {
2626
struct list_head list;
27+
struct list_head mod_list;
2728
const struct unwind_idx *start;
2829
const struct unwind_idx *origin;
2930
const struct unwind_idx *stop;

arch/arm/kernel/module.c

Lines changed: 40 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -459,46 +459,40 @@ int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
459459
#ifdef CONFIG_ARM_UNWIND
460460
const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
461461
const Elf_Shdr *sechdrs_end = sechdrs + hdr->e_shnum;
462-
struct mod_unwind_map maps[ARM_SEC_MAX];
463-
int i;
462+
struct list_head *unwind_list = &mod->arch.unwind_list;
464463

465-
memset(maps, 0, sizeof(maps));
464+
INIT_LIST_HEAD(unwind_list);
465+
mod->arch.init_table = NULL;
466466

467467
for (s = sechdrs; s < sechdrs_end; s++) {
468468
const char *secname = secstrs + s->sh_name;
469+
const char *txtname;
470+
const Elf_Shdr *txt_sec;
469471

470-
if (!(s->sh_flags & SHF_ALLOC))
472+
if (!(s->sh_flags & SHF_ALLOC) ||
473+
s->sh_type != ELF_SECTION_UNWIND)
471474
continue;
472475

473-
if (strcmp(".ARM.exidx.init.text", secname) == 0)
474-
maps[ARM_SEC_INIT].unw_sec = s;
475-
else if (strcmp(".ARM.exidx", secname) == 0)
476-
maps[ARM_SEC_CORE].unw_sec = s;
477-
else if (strcmp(".ARM.exidx.exit.text", secname) == 0)
478-
maps[ARM_SEC_EXIT].unw_sec = s;
479-
else if (strcmp(".ARM.exidx.text.unlikely", secname) == 0)
480-
maps[ARM_SEC_UNLIKELY].unw_sec = s;
481-
else if (strcmp(".ARM.exidx.text.hot", secname) == 0)
482-
maps[ARM_SEC_HOT].unw_sec = s;
483-
else if (strcmp(".init.text", secname) == 0)
484-
maps[ARM_SEC_INIT].txt_sec = s;
485-
else if (strcmp(".text", secname) == 0)
486-
maps[ARM_SEC_CORE].txt_sec = s;
487-
else if (strcmp(".exit.text", secname) == 0)
488-
maps[ARM_SEC_EXIT].txt_sec = s;
489-
else if (strcmp(".text.unlikely", secname) == 0)
490-
maps[ARM_SEC_UNLIKELY].txt_sec = s;
491-
else if (strcmp(".text.hot", secname) == 0)
492-
maps[ARM_SEC_HOT].txt_sec = s;
493-
}
476+
if (!strcmp(".ARM.exidx", secname))
477+
txtname = ".text";
478+
else
479+
txtname = secname + strlen(".ARM.exidx");
480+
txt_sec = find_mod_section(hdr, sechdrs, txtname);
481+
482+
if (txt_sec) {
483+
struct unwind_table *table =
484+
unwind_table_add(s->sh_addr,
485+
s->sh_size,
486+
txt_sec->sh_addr,
487+
txt_sec->sh_size);
494488

495-
for (i = 0; i < ARM_SEC_MAX; i++)
496-
if (maps[i].unw_sec && maps[i].txt_sec)
497-
mod->arch.unwind[i] =
498-
unwind_table_add(maps[i].unw_sec->sh_addr,
499-
maps[i].unw_sec->sh_size,
500-
maps[i].txt_sec->sh_addr,
501-
maps[i].txt_sec->sh_size);
489+
list_add(&table->mod_list, unwind_list);
490+
491+
/* save init table for module_arch_freeing_init */
492+
if (strcmp(".ARM.exidx.init.text", secname) == 0)
493+
mod->arch.init_table = table;
494+
}
495+
}
502496
#endif
503497
#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
504498
s = find_mod_section(hdr, sechdrs, ".pv_table");
@@ -519,19 +513,27 @@ void
519513
module_arch_cleanup(struct module *mod)
520514
{
521515
#ifdef CONFIG_ARM_UNWIND
522-
int i;
516+
struct unwind_table *tmp;
517+
struct unwind_table *n;
523518

524-
for (i = 0; i < ARM_SEC_MAX; i++) {
525-
unwind_table_del(mod->arch.unwind[i]);
526-
mod->arch.unwind[i] = NULL;
519+
list_for_each_entry_safe(tmp, n,
520+
&mod->arch.unwind_list, mod_list) {
521+
list_del(&tmp->mod_list);
522+
unwind_table_del(tmp);
527523
}
524+
mod->arch.init_table = NULL;
528525
#endif
529526
}
530527

531528
void __weak module_arch_freeing_init(struct module *mod)
532529
{
533530
#ifdef CONFIG_ARM_UNWIND
534-
unwind_table_del(mod->arch.unwind[ARM_SEC_INIT]);
535-
mod->arch.unwind[ARM_SEC_INIT] = NULL;
531+
struct unwind_table *init = mod->arch.init_table;
532+
533+
if (init) {
534+
mod->arch.init_table = NULL;
535+
list_del(&init->mod_list);
536+
unwind_table_del(init);
537+
}
536538
#endif
537539
}

0 commit comments

Comments
 (0)