diff options
author | Matt Fleming <matt@console-pimps.org> | 2009-10-09 23:20:54 +0100 |
---|---|---|
committer | Matt Fleming <matt@console-pimps.org> | 2009-10-11 16:41:44 +0100 |
commit | a6a2f2ad67506090e332f440457553c0ec011d68 (patch) | |
tree | cfe974784b68cc3c09ed76e449a31d536b2b4589 /arch/sh/kernel/module.c | |
parent | c153a58e715e16ffcd6c4b3da7fc6b4a556bf917 (diff) | |
download | op-kernel-dev-a6a2f2ad67506090e332f440457553c0ec011d68.zip op-kernel-dev-a6a2f2ad67506090e332f440457553c0ec011d68.tar.gz |
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 c2efdcd..d297a14 100644 --- a/arch/sh/kernel/module.c +++ b/arch/sh/kernel/module.c @@ -32,6 +32,7 @@ #include <linux/string.h> #include <linux/kernel.h> #include <asm/unaligned.h> +#include <asm/dwarf.h> void *module_alloc(unsigned long size) { @@ -145,10 +146,41 @@ int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *me) { +#ifdef CONFIG_DWARF_UNWINDER + unsigned int i, err; + unsigned long start, end; + char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; + + start = end = 0; + + for (i = 1; i < hdr->e_shnum; i++) { + /* Alloc bit cleared means "ignore it." */ + if ((sechdrs[i].sh_flags & SHF_ALLOC) + && !strcmp(secstrings+sechdrs[i].sh_name, ".eh_frame")) { + start = sechdrs[i].sh_addr; + end = start + sechdrs[i].sh_size; + break; + } + } + + /* Did we find the .eh_frame section? */ + if (i != hdr->e_shnum) { + err = dwarf_parse_section((char *)start, (char *)end, me); + if (err) + printk(KERN_WARNING "%s: failed to parse DWARF info\n", + me->name); + } + +#endif /* CONFIG_DWARF_UNWINDER */ + return module_bug_finalize(hdr, sechdrs, me); } void module_arch_cleanup(struct module *mod) { module_bug_cleanup(mod); + +#ifdef CONFIG_DWARF_UNWINDER + dwarf_module_unload(mod); +#endif /* CONFIG_DWARF_UNWINDER */ } |