diff options
author | Catalin Marinas <catalin.marinas@arm.com> | 2009-02-11 07:09:54 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-02-19 06:27:19 -0500 |
commit | 2e1926e7b5d39eb31880152d636e8d8d011888cb (patch) | |
tree | 3d871e05d14db1358f065cd87e310c6f59430cb8 /arch/arm/kernel | |
parent | bff595c15c92b9c5c8f3d32edefcef6c3cbdd59f (diff) |
[ARM] 5384/1: unwind: Add stack unwinding support for loadable modules
This patch adds ELF section parsing for the unwinding tables in loadable
modules together with the PREL31 relocation symbol resolving.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/module.c | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index dab48f27263f..13dbd5bf5cc2 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #include <asm/pgtable.h> | 23 | #include <asm/pgtable.h> |
24 | #include <asm/sections.h> | 24 | #include <asm/sections.h> |
25 | #include <asm/unwind.h> | ||
25 | 26 | ||
26 | #ifdef CONFIG_XIP_KERNEL | 27 | #ifdef CONFIG_XIP_KERNEL |
27 | /* | 28 | /* |
@@ -66,6 +67,24 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, | |||
66 | char *secstrings, | 67 | char *secstrings, |
67 | struct module *mod) | 68 | struct module *mod) |
68 | { | 69 | { |
70 | #ifdef CONFIG_ARM_UNWIND | ||
71 | Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum; | ||
72 | |||
73 | for (s = sechdrs; s < sechdrs_end; s++) { | ||
74 | if (strcmp(".ARM.exidx.init.text", secstrings + s->sh_name) == 0) | ||
75 | mod->arch.unw_sec_init = s; | ||
76 | else if (strcmp(".ARM.exidx.devinit.text", secstrings + s->sh_name) == 0) | ||
77 | mod->arch.unw_sec_devinit = s; | ||
78 | else if (strcmp(".ARM.exidx", secstrings + s->sh_name) == 0) | ||
79 | mod->arch.unw_sec_core = s; | ||
80 | else if (strcmp(".init.text", secstrings + s->sh_name) == 0) | ||
81 | mod->arch.sec_init_text = s; | ||
82 | else if (strcmp(".devinit.text", secstrings + s->sh_name) == 0) | ||
83 | mod->arch.sec_devinit_text = s; | ||
84 | else if (strcmp(".text", secstrings + s->sh_name) == 0) | ||
85 | mod->arch.sec_core_text = s; | ||
86 | } | ||
87 | #endif | ||
69 | return 0; | 88 | return 0; |
70 | } | 89 | } |
71 | 90 | ||
@@ -104,6 +123,10 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
104 | loc = dstsec->sh_addr + rel->r_offset; | 123 | loc = dstsec->sh_addr + rel->r_offset; |
105 | 124 | ||
106 | switch (ELF32_R_TYPE(rel->r_info)) { | 125 | switch (ELF32_R_TYPE(rel->r_info)) { |
126 | case R_ARM_NONE: | ||
127 | /* ignore */ | ||
128 | break; | ||
129 | |||
107 | case R_ARM_ABS32: | 130 | case R_ARM_ABS32: |
108 | *(u32 *)loc += sym->st_value; | 131 | *(u32 *)loc += sym->st_value; |
109 | break; | 132 | break; |
@@ -132,6 +155,11 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
132 | *(u32 *)loc |= offset & 0x00ffffff; | 155 | *(u32 *)loc |= offset & 0x00ffffff; |
133 | break; | 156 | break; |
134 | 157 | ||
158 | case R_ARM_PREL31: | ||
159 | offset = *(u32 *)loc + sym->st_value - loc; | ||
160 | *(u32 *)loc = offset & 0x7fffffff; | ||
161 | break; | ||
162 | |||
135 | default: | 163 | default: |
136 | printk(KERN_ERR "%s: unknown relocation: %u\n", | 164 | printk(KERN_ERR "%s: unknown relocation: %u\n", |
137 | module->name, ELF32_R_TYPE(rel->r_info)); | 165 | module->name, ELF32_R_TYPE(rel->r_info)); |
@@ -150,14 +178,50 @@ apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, | |||
150 | return -ENOEXEC; | 178 | return -ENOEXEC; |
151 | } | 179 | } |
152 | 180 | ||
181 | #ifdef CONFIG_ARM_UNWIND | ||
182 | static void register_unwind_tables(struct module *mod) | ||
183 | { | ||
184 | if (mod->arch.unw_sec_init && mod->arch.sec_init_text) | ||
185 | mod->arch.unwind_init = | ||
186 | unwind_table_add(mod->arch.unw_sec_init->sh_addr, | ||
187 | mod->arch.unw_sec_init->sh_size, | ||
188 | mod->arch.sec_init_text->sh_addr, | ||
189 | mod->arch.sec_init_text->sh_size); | ||
190 | if (mod->arch.unw_sec_devinit && mod->arch.sec_devinit_text) | ||
191 | mod->arch.unwind_devinit = | ||
192 | unwind_table_add(mod->arch.unw_sec_devinit->sh_addr, | ||
193 | mod->arch.unw_sec_devinit->sh_size, | ||
194 | mod->arch.sec_devinit_text->sh_addr, | ||
195 | mod->arch.sec_devinit_text->sh_size); | ||
196 | if (mod->arch.unw_sec_core && mod->arch.sec_core_text) | ||
197 | mod->arch.unwind_core = | ||
198 | unwind_table_add(mod->arch.unw_sec_core->sh_addr, | ||
199 | mod->arch.unw_sec_core->sh_size, | ||
200 | mod->arch.sec_core_text->sh_addr, | ||
201 | mod->arch.sec_core_text->sh_size); | ||
202 | } | ||
203 | |||
204 | static void unregister_unwind_tables(struct module *mod) | ||
205 | { | ||
206 | unwind_table_del(mod->arch.unwind_init); | ||
207 | unwind_table_del(mod->arch.unwind_devinit); | ||
208 | unwind_table_del(mod->arch.unwind_core); | ||
209 | } | ||
210 | #else | ||
211 | static inline void register_unwind_tables(struct module *mod) { } | ||
212 | static inline void unregister_unwind_tables(struct module *mod) { } | ||
213 | #endif | ||
214 | |||
153 | int | 215 | int |
154 | module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs, | 216 | module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs, |
155 | struct module *module) | 217 | struct module *module) |
156 | { | 218 | { |
219 | register_unwind_tables(module); | ||
157 | return 0; | 220 | return 0; |
158 | } | 221 | } |
159 | 222 | ||
160 | void | 223 | void |
161 | module_arch_cleanup(struct module *mod) | 224 | module_arch_cleanup(struct module *mod) |
162 | { | 225 | { |
226 | unregister_unwind_tables(mod); | ||
163 | } | 227 | } |