diff options
author | Vineet Gupta <vgupta@synopsys.com> | 2013-01-22 06:33:19 -0500 |
---|---|---|
committer | Vineet Gupta <vgupta@synopsys.com> | 2013-02-15 12:46:03 -0500 |
commit | 854a0d95056c265d96cb449bc97bc5ef9bbed835 (patch) | |
tree | 798c834ae188bd570b861a47765fce8ed633f85a /arch/arc/kernel/module.c | |
parent | 41195d236e84458bebd4fdc218610a92231ac791 (diff) |
ARC: DWARF2 .debug_frame based stack unwinder
-Originally written by Rajeshwar Ranga
-Derived off of generic unwinder in 2.6.19 and adapted to ARC
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Cc: Rajeshwar Ranga <rajeshwar.ranga@gmail.com>
Diffstat (limited to 'arch/arc/kernel/module.c')
-rw-r--r-- | arch/arc/kernel/module.c | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/arch/arc/kernel/module.c b/arch/arc/kernel/module.c index a1bb70d6e97d..cdd359352c0a 100644 --- a/arch/arc/kernel/module.c +++ b/arch/arc/kernel/module.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
15 | #include <linux/fs.h> | 15 | #include <linux/fs.h> |
16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
17 | #include <asm/unwind.h> | ||
17 | 18 | ||
18 | static inline void arc_write_me(unsigned short *addr, unsigned long value) | 19 | static inline void arc_write_me(unsigned short *addr, unsigned long value) |
19 | { | 20 | { |
@@ -21,6 +22,42 @@ static inline void arc_write_me(unsigned short *addr, unsigned long value) | |||
21 | *(addr + 1) = (value & 0xffff); | 22 | *(addr + 1) = (value & 0xffff); |
22 | } | 23 | } |
23 | 24 | ||
25 | /* ARC specific section quirks - before relocation loop in generic loader | ||
26 | * | ||
27 | * For dwarf unwinding out of modules, this needs to | ||
28 | * 1. Ensure the .debug_frame is allocatable (ARC Linker bug: despite | ||
29 | * -fasynchronous-unwind-tables it doesn't). | ||
30 | * 2. Since we are iterating thru sec hdr tbl anyways, make a note of | ||
31 | * the exact section index, for later use. | ||
32 | */ | ||
33 | int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, | ||
34 | char *secstr, struct module *mod) | ||
35 | { | ||
36 | #ifdef CONFIG_ARC_DW2_UNWIND | ||
37 | int i; | ||
38 | |||
39 | mod->arch.unw_sec_idx = 0; | ||
40 | mod->arch.unw_info = NULL; | ||
41 | |||
42 | for (i = 1; i < hdr->e_shnum; i++) { | ||
43 | if (strcmp(secstr+sechdrs[i].sh_name, ".debug_frame") == 0) { | ||
44 | sechdrs[i].sh_flags |= SHF_ALLOC; | ||
45 | mod->arch.unw_sec_idx = i; | ||
46 | break; | ||
47 | } | ||
48 | } | ||
49 | #endif | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | void module_arch_cleanup(struct module *mod) | ||
54 | { | ||
55 | #ifdef CONFIG_ARC_DW2_UNWIND | ||
56 | if (mod->arch.unw_info) | ||
57 | unwind_remove_table(mod->arch.unw_info, 0); | ||
58 | #endif | ||
59 | } | ||
60 | |||
24 | int apply_relocate_add(Elf32_Shdr *sechdrs, | 61 | int apply_relocate_add(Elf32_Shdr *sechdrs, |
25 | const char *strtab, | 62 | const char *strtab, |
26 | unsigned int symindex, /* sec index for sym tbl */ | 63 | unsigned int symindex, /* sec index for sym tbl */ |
@@ -85,3 +122,24 @@ relo_err: | |||
85 | return -ENOEXEC; | 122 | return -ENOEXEC; |
86 | 123 | ||
87 | } | 124 | } |
125 | |||
126 | /* Just before lift off: After sections have been relocated, we add the | ||
127 | * dwarf section to unwinder table pool | ||
128 | * This couldn't be done in module_frob_arch_sections() because | ||
129 | * relocations had not been applied by then | ||
130 | */ | ||
131 | int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs, | ||
132 | struct module *mod) | ||
133 | { | ||
134 | #ifdef CONFIG_ARC_DW2_UNWIND | ||
135 | void *unw; | ||
136 | int unwsec = mod->arch.unw_sec_idx; | ||
137 | |||
138 | if (unwsec) { | ||
139 | unw = unwind_add_table(mod, (void *)sechdrs[unwsec].sh_addr, | ||
140 | sechdrs[unwsec].sh_size); | ||
141 | mod->arch.unw_info = unw; | ||
142 | } | ||
143 | #endif | ||
144 | return 0; | ||
145 | } | ||