diff options
author | Matt Fleming <matt@console-pimps.org> | 2009-10-09 18:20:54 -0400 |
---|---|---|
committer | Matt Fleming <matt@console-pimps.org> | 2009-10-11 11:41:44 -0400 |
commit | a6a2f2ad67506090e332f440457553c0ec011d68 (patch) | |
tree | cfe974784b68cc3c09ed76e449a31d536b2b4589 /arch/sh/kernel/module.c | |
parent | c153a58e715e16ffcd6c4b3da7fc6b4a556bf917 (diff) |
sh: Teach the DWARF unwinder about modules
Pass a module's .eh_frame section to the DWARF unwinder at module load
time so that the section's FDEs and CIEs can be registered with the
DWARF unwinder. This allows us to unwind the stack through module code
when generating backtraces.
Signed-off-by: Matt Fleming <matt@console-pimps.org>
Diffstat (limited to 'arch/sh/kernel/module.c')
-rw-r--r-- | arch/sh/kernel/module.c | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/arch/sh/kernel/module.c b/arch/sh/kernel/module.c index c2efdcde266f..d297a148d16c 100644 --- a/arch/sh/kernel/module.c +++ b/arch/sh/kernel/module.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/string.h> | 32 | #include <linux/string.h> |
33 | #include <linux/kernel.h> | 33 | #include <linux/kernel.h> |
34 | #include <asm/unaligned.h> | 34 | #include <asm/unaligned.h> |
35 | #include <asm/dwarf.h> | ||
35 | 36 | ||
36 | void *module_alloc(unsigned long size) | 37 | void *module_alloc(unsigned long size) |
37 | { | 38 | { |
@@ -145,10 +146,41 @@ int module_finalize(const Elf_Ehdr *hdr, | |||
145 | const Elf_Shdr *sechdrs, | 146 | const Elf_Shdr *sechdrs, |
146 | struct module *me) | 147 | struct module *me) |
147 | { | 148 | { |
149 | #ifdef CONFIG_DWARF_UNWINDER | ||
150 | unsigned int i, err; | ||
151 | unsigned long start, end; | ||
152 | char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | ||
153 | |||
154 | start = end = 0; | ||
155 | |||
156 | for (i = 1; i < hdr->e_shnum; i++) { | ||
157 | /* Alloc bit cleared means "ignore it." */ | ||
158 | if ((sechdrs[i].sh_flags & SHF_ALLOC) | ||
159 | && !strcmp(secstrings+sechdrs[i].sh_name, ".eh_frame")) { | ||
160 | start = sechdrs[i].sh_addr; | ||
161 | end = start + sechdrs[i].sh_size; | ||
162 | break; | ||
163 | } | ||
164 | } | ||
165 | |||
166 | /* Did we find the .eh_frame section? */ | ||
167 | if (i != hdr->e_shnum) { | ||
168 | err = dwarf_parse_section((char *)start, (char *)end, me); | ||
169 | if (err) | ||
170 | printk(KERN_WARNING "%s: failed to parse DWARF info\n", | ||
171 | me->name); | ||
172 | } | ||
173 | |||
174 | #endif /* CONFIG_DWARF_UNWINDER */ | ||
175 | |||
148 | return module_bug_finalize(hdr, sechdrs, me); | 176 | return module_bug_finalize(hdr, sechdrs, me); |
149 | } | 177 | } |
150 | 178 | ||
151 | void module_arch_cleanup(struct module *mod) | 179 | void module_arch_cleanup(struct module *mod) |
152 | { | 180 | { |
153 | module_bug_cleanup(mod); | 181 | module_bug_cleanup(mod); |
182 | |||
183 | #ifdef CONFIG_DWARF_UNWINDER | ||
184 | dwarf_module_unload(mod); | ||
185 | #endif /* CONFIG_DWARF_UNWINDER */ | ||
154 | } | 186 | } |